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 Shadow texture lookup tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es3fTextureShadowTests.hpp"
25 #include "gluTexture.hpp"
26 #include "gluPixelTransfer.hpp"
27 #include "gluTextureUtil.hpp"
28 #include "glsTextureTestUtil.hpp"
29 #include "tcuTextureUtil.hpp"
30 #include "tcuRenderTarget.hpp"
31 #include "tcuTexCompareVerifier.hpp"
32 #include "tcuVectorUtil.hpp"
33 #include "deString.h"
34 #include "deMath.h"
35 #include "deStringUtil.hpp"
36 #include "glwFunctions.hpp"
37 #include "glwEnums.hpp"
38
39 namespace deqp
40 {
41 namespace gles3
42 {
43 namespace Functional
44 {
45
46 using std::vector;
47 using std::string;
48 using tcu::TestLog;
49 using namespace deqp::gls::TextureTestUtil;
50 using namespace glu::TextureTestUtil;
51
52 enum
53 {
54 TEX2D_VIEWPORT_WIDTH = 64,
55 TEX2D_VIEWPORT_HEIGHT = 64,
56 TEX2D_MIN_VIEWPORT_WIDTH = 64,
57 TEX2D_MIN_VIEWPORT_HEIGHT = 64
58 };
59
isFloatingPointDepthFormat(const tcu::TextureFormat& format)60 static bool isFloatingPointDepthFormat (const tcu::TextureFormat& format)
61 {
62 // Only two depth and depth-stencil formats are floating point
63 return (format.order == tcu::TextureFormat::D && format.type == tcu::TextureFormat::FLOAT) ||
64 (format.order == tcu::TextureFormat::DS && format.type == tcu::TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV);
65 }
66
clampFloatingPointTexture(const tcu::PixelBufferAccess& access)67 static void clampFloatingPointTexture (const tcu::PixelBufferAccess& access)
68 {
69 DE_ASSERT(isFloatingPointDepthFormat(access.getFormat()));
70
71 for (int z = 0; z < access.getDepth(); ++z)
72 for (int y = 0; y < access.getHeight(); ++y)
73 for (int x = 0; x < access.getWidth(); ++x)
74 access.setPixDepth( de::clamp(access.getPixDepth(x, y, z), 0.0f, 1.0f), x, y, z);
75 }
76
clampFloatingPointTexture(tcu::Texture2D& target)77 static void clampFloatingPointTexture (tcu::Texture2D& target)
78 {
79 for (int level = 0; level < target.getNumLevels(); ++level)
80 if (!target.isLevelEmpty(level))
81 clampFloatingPointTexture(target.getLevel(level));
82 }
83
clampFloatingPointTexture(tcu::Texture2DArray& target)84 static void clampFloatingPointTexture (tcu::Texture2DArray& target)
85 {
86 for (int level = 0; level < target.getNumLevels(); ++level)
87 if (!target.isLevelEmpty(level))
88 clampFloatingPointTexture(target.getLevel(level));
89 }
90
clampFloatingPointTexture(tcu::TextureCube& target)91 static void clampFloatingPointTexture (tcu::TextureCube& target)
92 {
93 for (int level = 0; level < target.getNumLevels(); ++level)
94 for (int face = tcu::CUBEFACE_NEGATIVE_X; face < tcu::CUBEFACE_LAST; ++face)
95 clampFloatingPointTexture(target.getLevelFace(level, (tcu::CubeFace)face));
96 }
97
98 template<typename TextureType>
verifyTexCompareResult(tcu::TestContext& testCtx, const tcu::ConstPixelBufferAccess& result, const TextureType& src, const float* texCoord, const ReferenceParams& sampleParams, const tcu::TexComparePrecision& comparePrec, const tcu::LodPrecision& lodPrec, const tcu::PixelFormat& pixelFormat)99 bool verifyTexCompareResult (tcu::TestContext& testCtx,
100 const tcu::ConstPixelBufferAccess& result,
101 const TextureType& src,
102 const float* texCoord,
103 const ReferenceParams& sampleParams,
104 const tcu::TexComparePrecision& comparePrec,
105 const tcu::LodPrecision& lodPrec,
106 const tcu::PixelFormat& pixelFormat)
107 {
108 tcu::TestLog& log = testCtx.getLog();
109 tcu::Surface reference (result.getWidth(), result.getHeight());
110 tcu::Surface errorMask (result.getWidth(), result.getHeight());
111 const tcu::IVec4 nonShadowBits = tcu::max(getBitsVec(pixelFormat)-1, tcu::IVec4(0));
112 const tcu::Vec3 nonShadowThreshold = tcu::computeFixedPointThreshold(nonShadowBits).swizzle(1,2,3);
113 int numFailedPixels;
114
115 // sampleTexture() expects source image to be the same state as it would be in a GL implementation, that is
116 // the floating point depth values should be in [0, 1] range as data is clamped during texture upload. Since
117 // we don't have a separate "uploading" phase and just reuse the buffer we used for GL-upload, do the clamping
118 // here if necessary.
119
120 if (isFloatingPointDepthFormat(src.getFormat()))
121 {
122 TextureType clampedSource(src);
123
124 clampFloatingPointTexture(clampedSource);
125
126 // sample clamped values
127
128 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), clampedSource, texCoord, sampleParams);
129 numFailedPixels = computeTextureCompareDiff(result, reference.getAccess(), errorMask.getAccess(), clampedSource, texCoord, sampleParams, comparePrec, lodPrec, nonShadowThreshold);
130 }
131 else
132 {
133 // sample raw values (they are guaranteed to be in [0, 1] range as the format cannot represent any other values)
134
135 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
136 numFailedPixels = computeTextureCompareDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, comparePrec, lodPrec, nonShadowThreshold);
137 }
138
139 if (numFailedPixels > 0)
140 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
141
142 log << TestLog::ImageSet("VerifyResult", "Verification result")
143 << TestLog::Image("Rendered", "Rendered image", result);
144
145 if (numFailedPixels > 0)
146 {
147 log << TestLog::Image("Reference", "Ideal reference image", reference)
148 << TestLog::Image("ErrorMask", "Error mask", errorMask);
149 }
150
151 log << TestLog::EndImageSet;
152
153 return numFailedPixels == 0;
154 }
155
156 class Texture2DShadowCase : public TestCase
157 {
158 public:
159 Texture2DShadowCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int width, int height, deUint32 compareFunc);
160 ~Texture2DShadowCase (void);
161
162 void init (void);
163 void deinit (void);
164 IterateResult iterate (void);
165
166 private:
167 Texture2DShadowCase (const Texture2DShadowCase& other);
168 Texture2DShadowCase& operator= (const Texture2DShadowCase& other);
169
170 const deUint32 m_minFilter;
171 const deUint32 m_magFilter;
172 const deUint32 m_wrapS;
173 const deUint32 m_wrapT;
174 const deUint32 m_format;
175 const int m_width;
176 const int m_height;
177 const deUint32 m_compareFunc;
178
179 struct FilterCase
180 {
181 const glu::Texture2D* texture;
182 tcu::Vec2 minCoord;
183 tcu::Vec2 maxCoord;
184 float ref;
185
FilterCasedeqp::gles3::Functional::Texture2DShadowCase::FilterCase186 FilterCase (void)
187 : texture (DE_NULL)
188 , ref (0.0f)
189 {
190 }
191
FilterCasedeqp::gles3::Functional::Texture2DShadowCase::FilterCase192 FilterCase (const glu::Texture2D* tex_, const float ref_, const tcu::Vec2& minCoord_, const tcu::Vec2& maxCoord_)
193 : texture (tex_)
194 , minCoord (minCoord_)
195 , maxCoord (maxCoord_)
196 , ref (ref_)
197 {
198 }
199 };
200
201 std::vector<glu::Texture2D*> m_textures;
202 std::vector<FilterCase> m_cases;
203
204 TextureRenderer m_renderer;
205
206 int m_caseNdx;
207 };
208
Texture2DShadowCase(Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int width, int height, deUint32 compareFunc)209 Texture2DShadowCase::Texture2DShadowCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int width, int height, deUint32 compareFunc)
210 : TestCase (context, name, desc)
211 , m_minFilter (minFilter)
212 , m_magFilter (magFilter)
213 , m_wrapS (wrapS)
214 , m_wrapT (wrapT)
215 , m_format (format)
216 , m_width (width)
217 , m_height (height)
218 , m_compareFunc (compareFunc)
219 , m_renderer (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
220 , m_caseNdx (0)
221 {
222 }
223
~Texture2DShadowCase(void)224 Texture2DShadowCase::~Texture2DShadowCase (void)
225 {
226 deinit();
227 }
228
init(void)229 void Texture2DShadowCase::init (void)
230 {
231 try
232 {
233 // Create 2 textures.
234 m_textures.reserve(2);
235 m_textures.push_back(new glu::Texture2D(m_context.getRenderContext(), m_format, m_width, m_height));
236 m_textures.push_back(new glu::Texture2D(m_context.getRenderContext(), m_format, m_width, m_height));
237
238 int numLevels = m_textures[0]->getRefTexture().getNumLevels();
239
240 // Fill first gradient texture.
241 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
242 {
243 m_textures[0]->getRefTexture().allocLevel(levelNdx);
244 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), tcu::Vec4(-0.5f, -0.5f, -0.5f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f));
245 }
246
247 // Fill second with grid texture.
248 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
249 {
250 deUint32 step = 0x00ffffff / numLevels;
251 deUint32 rgb = step*levelNdx;
252 deUint32 colorA = 0xff000000 | rgb;
253 deUint32 colorB = 0xff000000 | ~rgb;
254
255 m_textures[1]->getRefTexture().allocLevel(levelNdx);
256 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec(), tcu::RGBA(colorB).toVec());
257 }
258
259 // Upload.
260 for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
261 (*i)->upload();
262 }
263 catch (const std::exception&)
264 {
265 // Clean up to save memory.
266 Texture2DShadowCase::deinit();
267 throw;
268 }
269
270 // Compute cases.
271 {
272 const float refInRangeUpper = (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 1.0f : 0.5f;
273 const float refInRangeLower = (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 0.0f : 0.5f;
274 const float refOutOfBoundsUpper = 1.1f; // !< lookup function should clamp values to [0, 1] range
275 const float refOutOfBoundsLower = -0.1f;
276
277 const struct
278 {
279 int texNdx;
280 float ref;
281 float lodX;
282 float lodY;
283 float oX;
284 float oY;
285 } cases[] =
286 {
287 { 0, refInRangeUpper, 1.6f, 2.9f, -1.0f, -2.7f },
288 { 0, refInRangeLower, -2.0f, -1.35f, -0.2f, 0.7f },
289 { 1, refInRangeUpper, 0.14f, 0.275f, -1.5f, -1.1f },
290 { 1, refInRangeLower, -0.92f, -2.64f, 0.4f, -0.1f },
291 { 1, refOutOfBoundsUpper, -0.39f, -0.52f, 0.65f, 0.87f },
292 { 1, refOutOfBoundsLower, -1.55f, 0.65f, 0.35f, 0.91f },
293 };
294
295 const float viewportW = (float)de::min<int>(TEX2D_VIEWPORT_WIDTH, m_context.getRenderTarget().getWidth());
296 const float viewportH = (float)de::min<int>(TEX2D_VIEWPORT_HEIGHT, m_context.getRenderTarget().getHeight());
297
298 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
299 {
300 const int texNdx = de::clamp(cases[caseNdx].texNdx, 0, (int)m_textures.size()-1);
301 const float ref = cases[caseNdx].ref;
302 const float lodX = cases[caseNdx].lodX;
303 const float lodY = cases[caseNdx].lodY;
304 const float oX = cases[caseNdx].oX;
305 const float oY = cases[caseNdx].oY;
306 const float sX = deFloatExp2(lodX)*viewportW / float(m_textures[texNdx]->getRefTexture().getWidth());
307 const float sY = deFloatExp2(lodY)*viewportH / float(m_textures[texNdx]->getRefTexture().getHeight());
308
309 m_cases.push_back(FilterCase(m_textures[texNdx], ref, tcu::Vec2(oX, oY), tcu::Vec2(oX+sX, oY+sY)));
310 }
311 }
312
313 m_caseNdx = 0;
314 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
315 }
316
deinit(void)317 void Texture2DShadowCase::deinit (void)
318 {
319 for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
320 delete *i;
321 m_textures.clear();
322
323 m_renderer.clear();
324 m_cases.clear();
325 }
326
iterate(void)327 Texture2DShadowCase::IterateResult Texture2DShadowCase::iterate (void)
328 {
329 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
330 const RandomViewport viewport (m_context.getRenderTarget(), TEX2D_VIEWPORT_WIDTH, TEX2D_VIEWPORT_HEIGHT, deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
331 const FilterCase& curCase = m_cases[m_caseNdx];
332 const tcu::ScopedLogSection section (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
333 ReferenceParams sampleParams (TEXTURETYPE_2D);
334 tcu::Surface rendered (viewport.width, viewport.height);
335 vector<float> texCoord;
336
337 if (viewport.width < TEX2D_MIN_VIEWPORT_WIDTH || viewport.height < TEX2D_MIN_VIEWPORT_HEIGHT)
338 throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__);
339
340 // Setup params for reference.
341 sampleParams.sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
342 sampleParams.sampler.compare = glu::mapGLCompareFunc(m_compareFunc);
343 sampleParams.samplerType = SAMPLERTYPE_SHADOW;
344 sampleParams.lodMode = LODMODE_EXACT;
345 sampleParams.ref = curCase.ref;
346
347 m_testCtx.getLog() << TestLog::Message << "Compare reference value = " << sampleParams.ref << TestLog::EndMessage;
348
349 // Compute texture coordinates.
350 m_testCtx.getLog() << TestLog::Message << "Texture coordinates: " << curCase.minCoord << " -> " << curCase.maxCoord << TestLog::EndMessage;
351 computeQuadTexCoord2D(texCoord, curCase.minCoord, curCase.maxCoord);
352
353 gl.bindTexture (GL_TEXTURE_2D, curCase.texture->getGLTexture());
354 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter);
355 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter);
356 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS);
357 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT);
358 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
359 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, m_compareFunc);
360
361 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
362 m_renderer.renderQuad(0, &texCoord[0], sampleParams);
363 glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, rendered.getAccess());
364
365 {
366 const tcu::PixelFormat pixelFormat = m_context.getRenderTarget().getPixelFormat();
367 tcu::LodPrecision lodPrecision;
368 tcu::TexComparePrecision texComparePrecision;
369
370 lodPrecision.derivateBits = 18;
371 lodPrecision.lodBits = 6;
372 texComparePrecision.coordBits = tcu::IVec3(20,20,0);
373 texComparePrecision.uvwBits = tcu::IVec3(7,7,0);
374 texComparePrecision.pcfBits = 5;
375 texComparePrecision.referenceBits = 16;
376 texComparePrecision.resultBits = pixelFormat.redBits-1;
377
378 const bool isHighQuality = verifyTexCompareResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
379 &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
380
381 if (!isHighQuality)
382 {
383 m_testCtx.getLog() << TestLog::Message << "Warning: Verification assuming high-quality PCF filtering failed." << TestLog::EndMessage;
384
385 lodPrecision.lodBits = 4;
386 texComparePrecision.uvwBits = tcu::IVec3(4,4,0);
387 texComparePrecision.pcfBits = 0;
388
389 const bool isOk = verifyTexCompareResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
390 &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
391
392 if (!isOk)
393 {
394 m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
395 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
396 }
397 else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
398 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality result");
399 }
400 }
401
402 m_caseNdx += 1;
403 return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
404 }
405
406 class TextureCubeShadowCase : public TestCase
407 {
408 public:
409 TextureCubeShadowCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int size, deUint32 compareFunc);
410 ~TextureCubeShadowCase (void);
411
412 void init (void);
413 void deinit (void);
414 IterateResult iterate (void);
415
416 private:
417 TextureCubeShadowCase (const TextureCubeShadowCase& other);
418 TextureCubeShadowCase& operator= (const TextureCubeShadowCase& other);
419
420 const deUint32 m_minFilter;
421 const deUint32 m_magFilter;
422 const deUint32 m_wrapS;
423 const deUint32 m_wrapT;
424
425 const deUint32 m_format;
426 const int m_size;
427
428 const deUint32 m_compareFunc;
429
430 struct FilterCase
431 {
432 const glu::TextureCube* texture;
433 tcu::Vec2 bottomLeft;
434 tcu::Vec2 topRight;
435 float ref;
436
FilterCasedeqp::gles3::Functional::TextureCubeShadowCase::FilterCase437 FilterCase (void)
438 : texture (DE_NULL)
439 , ref (0.0f)
440 {
441 }
442
FilterCasedeqp::gles3::Functional::TextureCubeShadowCase::FilterCase443 FilterCase (const glu::TextureCube* tex_, const float ref_, const tcu::Vec2& bottomLeft_, const tcu::Vec2& topRight_)
444 : texture (tex_)
445 , bottomLeft(bottomLeft_)
446 , topRight (topRight_)
447 , ref (ref_)
448 {
449 }
450 };
451
452 glu::TextureCube* m_gradientTex;
453 glu::TextureCube* m_gridTex;
454 std::vector<FilterCase> m_cases;
455
456 TextureRenderer m_renderer;
457
458 int m_caseNdx;
459 };
460
TextureCubeShadowCase(Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int size, deUint32 compareFunc)461 TextureCubeShadowCase::TextureCubeShadowCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int size, deUint32 compareFunc)
462 : TestCase (context, name, desc)
463 , m_minFilter (minFilter)
464 , m_magFilter (magFilter)
465 , m_wrapS (wrapS)
466 , m_wrapT (wrapT)
467 , m_format (format)
468 , m_size (size)
469 , m_compareFunc (compareFunc)
470 , m_gradientTex (DE_NULL)
471 , m_gridTex (DE_NULL)
472 , m_renderer (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
473 , m_caseNdx (0)
474 {
475 }
476
~TextureCubeShadowCase(void)477 TextureCubeShadowCase::~TextureCubeShadowCase (void)
478 {
479 TextureCubeShadowCase::deinit();
480 }
481
init(void)482 void TextureCubeShadowCase::init (void)
483 {
484 try
485 {
486 DE_ASSERT(!m_gradientTex && !m_gridTex);
487
488 int numLevels = deLog2Floor32(m_size)+1;
489 tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_format);
490 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
491 tcu::Vec4 cBias = fmtInfo.valueMin;
492 tcu::Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin;
493
494 // Create textures.
495 m_gradientTex = new glu::TextureCube(m_context.getRenderContext(), m_format, m_size);
496 m_gridTex = new glu::TextureCube(m_context.getRenderContext(), m_format, m_size);
497
498 // Fill first with gradient texture.
499 static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] =
500 {
501 { tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x
502 { tcu::Vec4( 0.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x
503 { tcu::Vec4(-1.0f, 0.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y
504 { tcu::Vec4(-1.0f, -1.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y
505 { tcu::Vec4(-1.0f, -1.0f, -1.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z
506 { tcu::Vec4( 0.0f, 0.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) } // positive z
507 };
508 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
509 {
510 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
511 {
512 m_gradientTex->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
513 tcu::fillWithComponentGradients(m_gradientTex->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias);
514 }
515 }
516
517 // Fill second with grid texture.
518 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
519 {
520 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
521 {
522 deUint32 step = 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST);
523 deUint32 rgb = step*levelNdx*face;
524 deUint32 colorA = 0xff000000 | rgb;
525 deUint32 colorB = 0xff000000 | ~rgb;
526
527 m_gridTex->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
528 tcu::fillWithGrid(m_gridTex->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
529 }
530 }
531
532 // Upload.
533 m_gradientTex->upload();
534 m_gridTex->upload();
535 }
536 catch (const std::exception&)
537 {
538 // Clean up to save memory.
539 TextureCubeShadowCase::deinit();
540 throw;
541 }
542
543 // Compute cases
544 {
545 const float refInRangeUpper = (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 1.0f : 0.5f;
546 const float refInRangeLower = (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 0.0f : 0.5f;
547 const float refOutOfBoundsUpper = 1.1f;
548 const float refOutOfBoundsLower = -0.1f;
549 const bool singleSample = m_context.getRenderTarget().getNumSamples() == 0;
550
551 if (singleSample)
552 m_cases.push_back(FilterCase(m_gradientTex, refInRangeUpper, tcu::Vec2(-1.25f, -1.2f), tcu::Vec2(1.2f, 1.25f))); // minification
553 else
554 m_cases.push_back(FilterCase(m_gradientTex, refInRangeUpper, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f))); // minification - w/ tuned coordinates to avoid hitting triangle edges
555
556 m_cases.push_back(FilterCase(m_gradientTex, refInRangeLower, tcu::Vec2(0.8f, 0.8f), tcu::Vec2(1.25f, 1.20f))); // magnification
557 m_cases.push_back(FilterCase(m_gridTex, refInRangeUpper, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f))); // minification
558 m_cases.push_back(FilterCase(m_gridTex, refInRangeLower, tcu::Vec2(-1.2f, -1.1f), tcu::Vec2(-0.8f, -0.8f))); // magnification
559 m_cases.push_back(FilterCase(m_gridTex, refOutOfBoundsUpper, tcu::Vec2(-0.61f, -0.1f), tcu::Vec2(0.9f, 1.18f))); // reference value clamp, upper
560
561 if (singleSample)
562 m_cases.push_back(FilterCase(m_gridTex, refOutOfBoundsLower, tcu::Vec2(-0.75f, 1.0f), tcu::Vec2(0.05f, 0.75f))); // reference value clamp, lower
563 else
564 m_cases.push_back(FilterCase(m_gridTex, refOutOfBoundsLower, tcu::Vec2(-0.75f, 1.0f), tcu::Vec2(0.25f, 0.75f))); // reference value clamp, lower
565 }
566
567 m_caseNdx = 0;
568 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
569 }
570
deinit(void)571 void TextureCubeShadowCase::deinit (void)
572 {
573 delete m_gradientTex;
574 delete m_gridTex;
575
576 m_gradientTex = DE_NULL;
577 m_gridTex = DE_NULL;
578
579 m_renderer.clear();
580 m_cases.clear();
581 }
582
getFaceDesc(const tcu::CubeFace face)583 static const char* getFaceDesc (const tcu::CubeFace face)
584 {
585 switch (face)
586 {
587 case tcu::CUBEFACE_NEGATIVE_X: return "-X";
588 case tcu::CUBEFACE_POSITIVE_X: return "+X";
589 case tcu::CUBEFACE_NEGATIVE_Y: return "-Y";
590 case tcu::CUBEFACE_POSITIVE_Y: return "+Y";
591 case tcu::CUBEFACE_NEGATIVE_Z: return "-Z";
592 case tcu::CUBEFACE_POSITIVE_Z: return "+Z";
593 default:
594 DE_ASSERT(false);
595 return DE_NULL;
596 }
597 }
598
iterate(void)599 TextureCubeShadowCase::IterateResult TextureCubeShadowCase::iterate (void)
600 {
601 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
602 const int viewportSize = 28;
603 const RandomViewport viewport (m_context.getRenderTarget(), viewportSize, viewportSize, deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
604 const tcu::ScopedLogSection iterSection (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
605 const FilterCase& curCase = m_cases[m_caseNdx];
606 ReferenceParams sampleParams (TEXTURETYPE_CUBE);
607
608 if (viewport.width < viewportSize || viewport.height < viewportSize)
609 throw tcu::NotSupportedError("Too small render target", DE_NULL, __FILE__, __LINE__);
610
611 // Setup texture
612 gl.bindTexture (GL_TEXTURE_CUBE_MAP, curCase.texture->getGLTexture());
613 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter);
614 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter);
615 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS);
616 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT);
617 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
618 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_FUNC, m_compareFunc);
619
620 // Other state
621 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
622
623 // Params for reference computation.
624 sampleParams.sampler = glu::mapGLSampler(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, m_minFilter, m_magFilter);
625 sampleParams.sampler.seamlessCubeMap = true;
626 sampleParams.sampler.compare = glu::mapGLCompareFunc(m_compareFunc);
627 sampleParams.samplerType = SAMPLERTYPE_SHADOW;
628 sampleParams.lodMode = LODMODE_EXACT;
629 sampleParams.ref = curCase.ref;
630
631 m_testCtx.getLog()
632 << TestLog::Message
633 << "Compare reference value = " << sampleParams.ref << "\n"
634 << "Coordinates: " << curCase.bottomLeft << " -> " << curCase.topRight
635 << TestLog::EndMessage;
636
637 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
638 {
639 const tcu::CubeFace face = tcu::CubeFace(faceNdx);
640 tcu::Surface result (viewport.width, viewport.height);
641 vector<float> texCoord;
642
643 computeQuadTexCoordCube(texCoord, face, curCase.bottomLeft, curCase.topRight);
644
645 m_testCtx.getLog() << TestLog::Message << "Face " << getFaceDesc(face) << TestLog::EndMessage;
646
647 // \todo Log texture coordinates.
648
649 m_renderer.renderQuad(0, &texCoord[0], sampleParams);
650 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
651
652 glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, result.getAccess());
653 GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
654
655 {
656 const tcu::PixelFormat pixelFormat = m_context.getRenderTarget().getPixelFormat();
657 tcu::LodPrecision lodPrecision;
658 tcu::TexComparePrecision texComparePrecision;
659
660 lodPrecision.derivateBits = 10;
661 lodPrecision.lodBits = 5;
662 texComparePrecision.coordBits = tcu::IVec3(10,10,10);
663 texComparePrecision.uvwBits = tcu::IVec3(6,6,0);
664 texComparePrecision.pcfBits = 5;
665 texComparePrecision.referenceBits = 16;
666 texComparePrecision.resultBits = pixelFormat.redBits-1;
667
668 const bool isHighQuality = verifyTexCompareResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
669 &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
670
671 if (!isHighQuality)
672 {
673 m_testCtx.getLog() << TestLog::Message << "Warning: Verification assuming high-quality PCF filtering failed." << TestLog::EndMessage;
674
675 lodPrecision.lodBits = 4;
676 texComparePrecision.uvwBits = tcu::IVec3(4,4,0);
677 texComparePrecision.pcfBits = 0;
678
679 const bool isOk = verifyTexCompareResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
680 &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
681
682 if (!isOk)
683 {
684 m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
685 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
686 }
687 else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
688 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality result");
689 }
690 }
691 }
692
693 m_caseNdx += 1;
694 return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
695 }
696
697 class Texture2DArrayShadowCase : public TestCase
698 {
699 public:
700 Texture2DArrayShadowCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int width, int height, int numLayers, deUint32 compareFunc);
701 ~Texture2DArrayShadowCase (void);
702
703 void init (void);
704 void deinit (void);
705 IterateResult iterate (void);
706
707 private:
708 Texture2DArrayShadowCase (const Texture2DArrayShadowCase& other);
709 Texture2DArrayShadowCase& operator= (const Texture2DArrayShadowCase& other);
710
711 const deUint32 m_minFilter;
712 const deUint32 m_magFilter;
713 const deUint32 m_wrapS;
714 const deUint32 m_wrapT;
715
716 const deUint32 m_format;
717 const int m_width;
718 const int m_height;
719 const int m_numLayers;
720
721 const deUint32 m_compareFunc;
722
723 struct FilterCase
724 {
725 const glu::Texture2DArray* texture;
726 tcu::Vec3 minCoord;
727 tcu::Vec3 maxCoord;
728 float ref;
729
FilterCasedeqp::gles3::Functional::Texture2DArrayShadowCase::FilterCase730 FilterCase (void)
731 : texture (DE_NULL)
732 , ref (0.0f)
733 {
734 }
735
FilterCasedeqp::gles3::Functional::Texture2DArrayShadowCase::FilterCase736 FilterCase (const glu::Texture2DArray* tex_, float ref_, const tcu::Vec3& minCoord_, const tcu::Vec3& maxCoord_)
737 : texture (tex_)
738 , minCoord (minCoord_)
739 , maxCoord (maxCoord_)
740 , ref (ref_)
741 {
742 }
743 };
744
745 glu::Texture2DArray* m_gradientTex;
746 glu::Texture2DArray* m_gridTex;
747 std::vector<FilterCase> m_cases;
748
749 TextureRenderer m_renderer;
750
751 int m_caseNdx;
752 };
753
Texture2DArrayShadowCase(Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int width, int height, int numLayers, deUint32 compareFunc)754 Texture2DArrayShadowCase::Texture2DArrayShadowCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int width, int height, int numLayers, deUint32 compareFunc)
755 : TestCase (context, name, desc)
756 , m_minFilter (minFilter)
757 , m_magFilter (magFilter)
758 , m_wrapS (wrapS)
759 , m_wrapT (wrapT)
760 , m_format (format)
761 , m_width (width)
762 , m_height (height)
763 , m_numLayers (numLayers)
764 , m_compareFunc (compareFunc)
765 , m_gradientTex (DE_NULL)
766 , m_gridTex (DE_NULL)
767 , m_renderer (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
768 , m_caseNdx (0)
769 {
770 }
771
~Texture2DArrayShadowCase(void)772 Texture2DArrayShadowCase::~Texture2DArrayShadowCase (void)
773 {
774 Texture2DArrayShadowCase::deinit();
775 }
776
init(void)777 void Texture2DArrayShadowCase::init (void)
778 {
779 try
780 {
781 tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_format);
782 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
783 tcu::Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin;
784 tcu::Vec4 cBias = fmtInfo.valueMin;
785 int numLevels = deLog2Floor32(de::max(m_width, m_height)) + 1;
786
787 // Create textures.
788 m_gradientTex = new glu::Texture2DArray(m_context.getRenderContext(), m_format, m_width, m_height, m_numLayers);
789 m_gridTex = new glu::Texture2DArray(m_context.getRenderContext(), m_format, m_width, m_height, m_numLayers);
790
791 // Fill first gradient texture.
792 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
793 {
794 tcu::Vec4 gMin = tcu::Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias;
795 tcu::Vec4 gMax = tcu::Vec4( 1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias;
796
797 m_gradientTex->getRefTexture().allocLevel(levelNdx);
798 tcu::fillWithComponentGradients(m_gradientTex->getRefTexture().getLevel(levelNdx), gMin, gMax);
799 }
800
801 // Fill second with grid texture.
802 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
803 {
804 deUint32 step = 0x00ffffff / numLevels;
805 deUint32 rgb = step*levelNdx;
806 deUint32 colorA = 0xff000000 | rgb;
807 deUint32 colorB = 0xff000000 | ~rgb;
808
809 m_gridTex->getRefTexture().allocLevel(levelNdx);
810 tcu::fillWithGrid(m_gridTex->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
811 }
812
813 // Upload.
814 m_gradientTex->upload();
815 m_gridTex->upload();
816 }
817 catch (...)
818 {
819 // Clean up to save memory.
820 Texture2DArrayShadowCase::deinit();
821 throw;
822 }
823
824 // Compute cases.
825 {
826 const float refInRangeUpper = (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 1.0f : 0.5f;
827 const float refInRangeLower = (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 0.0f : 0.5f;
828 const float refOutOfBoundsUpper = 1.1f; // !< lookup function should clamp values to [0, 1] range
829 const float refOutOfBoundsLower = -0.1f;
830
831 const struct
832 {
833 int texNdx;
834 float ref;
835 float lodX;
836 float lodY;
837 float oX;
838 float oY;
839 } cases[] =
840 {
841 { 0, refInRangeUpper, 1.6f, 2.9f, -1.0f, -2.7f },
842 { 0, refInRangeLower, -2.0f, -1.35f, -0.2f, 0.7f },
843 { 1, refInRangeUpper, 0.14f, 0.275f, -1.5f, -1.1f },
844 { 1, refInRangeLower, -0.92f, -2.64f, 0.4f, -0.1f },
845 { 1, refOutOfBoundsUpper, -0.49f, -0.22f, 0.45f, 0.97f },
846 { 1, refOutOfBoundsLower, -0.85f, 0.75f, 0.25f, 0.61f },
847 };
848
849 const float viewportW = (float)de::min<int>(TEX2D_VIEWPORT_WIDTH, m_context.getRenderTarget().getWidth());
850 const float viewportH = (float)de::min<int>(TEX2D_VIEWPORT_HEIGHT, m_context.getRenderTarget().getHeight());
851
852 const float minLayer = -0.5f;
853 const float maxLayer = (float)m_numLayers;
854
855 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
856 {
857 const glu::Texture2DArray* tex = cases[caseNdx].texNdx > 0 ? m_gridTex : m_gradientTex;
858 const float ref = cases[caseNdx].ref;
859 const float lodX = cases[caseNdx].lodX;
860 const float lodY = cases[caseNdx].lodY;
861 const float oX = cases[caseNdx].oX;
862 const float oY = cases[caseNdx].oY;
863 const float sX = deFloatExp2(lodX)*viewportW / float(tex->getRefTexture().getWidth());
864 const float sY = deFloatExp2(lodY)*viewportH / float(tex->getRefTexture().getHeight());
865
866 m_cases.push_back(FilterCase(tex, ref, tcu::Vec3(oX, oY, minLayer), tcu::Vec3(oX+sX, oY+sY, maxLayer)));
867 }
868 }
869
870 m_caseNdx = 0;
871 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
872 }
873
deinit(void)874 void Texture2DArrayShadowCase::deinit (void)
875 {
876 delete m_gradientTex;
877 delete m_gridTex;
878
879 m_gradientTex = DE_NULL;
880 m_gridTex = DE_NULL;
881
882 m_renderer.clear();
883 m_cases.clear();
884 }
885
iterate(void)886 Texture2DArrayShadowCase::IterateResult Texture2DArrayShadowCase::iterate (void)
887 {
888 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
889 const RandomViewport viewport (m_context.getRenderTarget(), TEX2D_VIEWPORT_WIDTH, TEX2D_VIEWPORT_HEIGHT, deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
890 const FilterCase& curCase = m_cases[m_caseNdx];
891 const tcu::ScopedLogSection section (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
892 ReferenceParams sampleParams (TEXTURETYPE_2D_ARRAY);
893 tcu::Surface rendered (viewport.width, viewport.height);
894
895 const float texCoord[] =
896 {
897 curCase.minCoord.x(), curCase.minCoord.y(), curCase.minCoord.z(),
898 curCase.minCoord.x(), curCase.maxCoord.y(), (curCase.minCoord.z() + curCase.maxCoord.z()) / 2.0f,
899 curCase.maxCoord.x(), curCase.minCoord.y(), (curCase.minCoord.z() + curCase.maxCoord.z()) / 2.0f,
900 curCase.maxCoord.x(), curCase.maxCoord.y(), curCase.maxCoord.z()
901 };
902
903 if (viewport.width < TEX2D_MIN_VIEWPORT_WIDTH || viewport.height < TEX2D_MIN_VIEWPORT_HEIGHT)
904 throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__);
905
906 // Setup params for reference.
907 sampleParams.sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
908 sampleParams.sampler.compare = glu::mapGLCompareFunc(m_compareFunc);
909 sampleParams.samplerType = SAMPLERTYPE_SHADOW;
910 sampleParams.lodMode = LODMODE_EXACT;
911 sampleParams.ref = curCase.ref;
912
913 m_testCtx.getLog()
914 << TestLog::Message
915 << "Compare reference value = " << sampleParams.ref << "\n"
916 << "Texture coordinates: " << curCase.minCoord << " -> " << curCase.maxCoord
917 << TestLog::EndMessage;
918
919 gl.bindTexture (GL_TEXTURE_2D_ARRAY, curCase.texture->getGLTexture());
920 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, m_minFilter);
921 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, m_magFilter);
922 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, m_wrapS);
923 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, m_wrapT);
924 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
925 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, m_compareFunc);
926
927 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
928 m_renderer.renderQuad(0, &texCoord[0], sampleParams);
929 glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, rendered.getAccess());
930
931 {
932 const tcu::PixelFormat pixelFormat = m_context.getRenderTarget().getPixelFormat();
933 tcu::LodPrecision lodPrecision;
934 tcu::TexComparePrecision texComparePrecision;
935
936 lodPrecision.derivateBits = 18;
937 lodPrecision.lodBits = 6;
938 texComparePrecision.coordBits = tcu::IVec3(20,20,20);
939 texComparePrecision.uvwBits = tcu::IVec3(7,7,7);
940 texComparePrecision.pcfBits = 5;
941 texComparePrecision.referenceBits = 16;
942 texComparePrecision.resultBits = pixelFormat.redBits-1;
943
944 const bool isHighQuality = verifyTexCompareResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
945 &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
946
947 if (!isHighQuality)
948 {
949 m_testCtx.getLog() << TestLog::Message << "Warning: Verification assuming high-quality PCF filtering failed." << TestLog::EndMessage;
950
951 lodPrecision.lodBits = 4;
952 texComparePrecision.uvwBits = tcu::IVec3(4,4,4);
953 texComparePrecision.pcfBits = 0;
954
955 const bool isOk = verifyTexCompareResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
956 &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
957
958 if (!isOk)
959 {
960 m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
961 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
962 }
963 else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
964 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality result");
965 }
966 }
967
968 m_caseNdx += 1;
969 return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
970 }
971
TextureShadowTests(Context& context)972 TextureShadowTests::TextureShadowTests (Context& context)
973 : TestCaseGroup(context, "shadow", "Shadow texture lookup tests")
974 {
975 }
976
~TextureShadowTests(void)977 TextureShadowTests::~TextureShadowTests (void)
978 {
979 }
980
init(void)981 void TextureShadowTests::init (void)
982 {
983 static const struct
984 {
985 const char* name;
986 deUint32 format;
987 } formats[] =
988 {
989 { "depth_component16", GL_DEPTH_COMPONENT16 },
990 { "depth_component32f", GL_DEPTH_COMPONENT32F },
991 { "depth24_stencil8", GL_DEPTH24_STENCIL8 }
992 };
993
994 static const struct
995 {
996 const char* name;
997 deUint32 minFilter;
998 deUint32 magFilter;
999 } filters[] =
1000 {
1001 { "nearest", GL_NEAREST, GL_NEAREST },
1002 { "linear", GL_LINEAR, GL_LINEAR },
1003 { "nearest_mipmap_nearest", GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR },
1004 { "linear_mipmap_nearest", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR },
1005 { "nearest_mipmap_linear", GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR },
1006 { "linear_mipmap_linear", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR }
1007 };
1008
1009 static const struct
1010 {
1011 const char* name;
1012 deUint32 func;
1013 } compareFuncs[] =
1014 {
1015 { "less_or_equal", GL_LEQUAL },
1016 { "greater_or_equal", GL_GEQUAL },
1017 { "less", GL_LESS },
1018 { "greater", GL_GREATER },
1019 { "equal", GL_EQUAL },
1020 { "not_equal", GL_NOTEQUAL },
1021 { "always", GL_ALWAYS },
1022 { "never", GL_NEVER }
1023 };
1024
1025 // 2D cases.
1026 {
1027 tcu::TestCaseGroup* group2D = new tcu::TestCaseGroup(m_testCtx, "2d", "2D texture shadow lookup tests");
1028 addChild(group2D);
1029
1030 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(filters); filterNdx++)
1031 {
1032 tcu::TestCaseGroup* filterGroup = new tcu::TestCaseGroup(m_testCtx, filters[filterNdx].name, "");
1033 group2D->addChild(filterGroup);
1034
1035 for (int compareNdx = 0; compareNdx < DE_LENGTH_OF_ARRAY(compareFuncs); compareNdx++)
1036 {
1037 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
1038 {
1039 deUint32 minFilter = filters[filterNdx].minFilter;
1040 deUint32 magFilter = filters[filterNdx].magFilter;
1041 deUint32 format = formats[formatNdx].format;
1042 deUint32 compareFunc = compareFuncs[compareNdx].func;
1043 const deUint32 wrapS = GL_REPEAT;
1044 const deUint32 wrapT = GL_REPEAT;
1045 const int width = 32;
1046 const int height = 64;
1047 string name = string(compareFuncs[compareNdx].name) + "_" + formats[formatNdx].name;
1048
1049 filterGroup->addChild(new Texture2DShadowCase(m_context, name.c_str(), "", minFilter, magFilter, wrapS, wrapT, format, width, height, compareFunc));
1050 }
1051 }
1052 }
1053 }
1054
1055 // Cubemap cases.
1056 {
1057 tcu::TestCaseGroup* groupCube = new tcu::TestCaseGroup(m_testCtx, "cube", "Cube map texture shadow lookup tests");
1058 addChild(groupCube);
1059
1060 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(filters); filterNdx++)
1061 {
1062 tcu::TestCaseGroup* filterGroup = new tcu::TestCaseGroup(m_testCtx, filters[filterNdx].name, "");
1063 groupCube->addChild(filterGroup);
1064
1065 for (int compareNdx = 0; compareNdx < DE_LENGTH_OF_ARRAY(compareFuncs); compareNdx++)
1066 {
1067 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
1068 {
1069 deUint32 minFilter = filters[filterNdx].minFilter;
1070 deUint32 magFilter = filters[filterNdx].magFilter;
1071 deUint32 format = formats[formatNdx].format;
1072 deUint32 compareFunc = compareFuncs[compareNdx].func;
1073 const deUint32 wrapS = GL_REPEAT;
1074 const deUint32 wrapT = GL_REPEAT;
1075 const int size = 32;
1076 string name = string(compareFuncs[compareNdx].name) + "_" + formats[formatNdx].name;
1077
1078 filterGroup->addChild(new TextureCubeShadowCase(m_context, name.c_str(), "", minFilter, magFilter, wrapS, wrapT, format, size, compareFunc));
1079 }
1080 }
1081 }
1082 }
1083
1084 // 2D array cases.
1085 {
1086 tcu::TestCaseGroup* group2DArray = new tcu::TestCaseGroup(m_testCtx, "2d_array", "2D texture array shadow lookup tests");
1087 addChild(group2DArray);
1088
1089 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(filters); filterNdx++)
1090 {
1091 tcu::TestCaseGroup* filterGroup = new tcu::TestCaseGroup(m_testCtx, filters[filterNdx].name, "");
1092 group2DArray->addChild(filterGroup);
1093
1094 for (int compareNdx = 0; compareNdx < DE_LENGTH_OF_ARRAY(compareFuncs); compareNdx++)
1095 {
1096 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
1097 {
1098 deUint32 minFilter = filters[filterNdx].minFilter;
1099 deUint32 magFilter = filters[filterNdx].magFilter;
1100 deUint32 format = formats[formatNdx].format;
1101 deUint32 compareFunc = compareFuncs[compareNdx].func;
1102 const deUint32 wrapS = GL_REPEAT;
1103 const deUint32 wrapT = GL_REPEAT;
1104 const int width = 32;
1105 const int height = 64;
1106 const int numLayers = 8;
1107 string name = string(compareFuncs[compareNdx].name) + "_" + formats[formatNdx].name;
1108
1109 filterGroup->addChild(new Texture2DArrayShadowCase(m_context, name.c_str(), "", minFilter, magFilter, wrapS, wrapT, format, width, height, numLayers, compareFunc));
1110 }
1111 }
1112 }
1113 }
1114 }
1115
1116 } // Functional
1117 } // gles3
1118 } // deqp
1119