1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Texture filtering accuracy tests.
22 *//*--------------------------------------------------------------------*/
24 #include "es3aTextureFilteringTests.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 "deStringUtil.hpp"
34 #include "glwFunctions.hpp"
35 #include "glwEnums.hpp"
47 using namespace gls::TextureTestUtil;
48 using namespace glu::TextureTestUtil;
50 class Texture2DFilteringCase : public tcu::TestCase
53 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);
54 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);
55 ~Texture2DFilteringCase (void);
59 IterateResult iterate (void);
62 Texture2DFilteringCase (const Texture2DFilteringCase& other);
63 Texture2DFilteringCase& operator= (const Texture2DFilteringCase& other);
65 glu::RenderContext& m_renderCtx;
66 const glu::ContextInfo& m_renderCtxInfo;
73 deUint32 m_internalFormat;
77 std::vector<std::string> m_filenames;
79 std::vector<glu::Texture2D*> m_textures;
80 TextureRenderer m_renderer;
83 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)
84 : TestCase (testCtx, tcu::NODETYPE_ACCURACY, name, desc)
85 , m_renderCtx (renderCtx)
86 , m_renderCtxInfo (ctxInfo)
87 , m_minFilter (minFilter)
88 , m_magFilter (magFilter)
91 , m_internalFormat (internalFormat)
94 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
98 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)
99 : TestCase (testCtx, tcu::NODETYPE_ACCURACY, name, desc)
100 , m_renderCtx (renderCtx)
101 , m_renderCtxInfo (ctxInfo)
102 , m_minFilter (minFilter)
103 , m_magFilter (magFilter)
106 , m_internalFormat (GL_NONE)
109 , m_filenames (filenames)
110 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_HIGHP)
114 Texture2DFilteringCase::~Texture2DFilteringCase (void)
119 void Texture2DFilteringCase::init (void)
123 if (!m_filenames.empty())
125 m_textures.reserve(1);
126 m_textures.push_back(glu::Texture2D::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(), (int)m_filenames.size(), m_filenames));
130 // Create 2 textures.
131 m_textures.reserve(2);
132 for (int ndx = 0; ndx < 2; ndx++)
133 m_textures.push_back(new glu::Texture2D(m_renderCtx, m_internalFormat, m_width, m_height));
135 const int numLevels = deLog2Floor32(de::max(m_width, m_height))+1;
136 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
137 tcu::Vec4 cBias = fmtInfo.valueMin;
138 tcu::Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin;
140 // Fill first gradient texture.
141 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
143 tcu::Vec4 gMin = tcu::Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias;
144 tcu::Vec4 gMax = tcu::Vec4( 1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias;
146 m_textures[0]->getRefTexture().allocLevel(levelNdx);
147 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax);
150 // Fill second with grid texture.
151 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
153 deUint32 step = 0x00ffffff / numLevels;
154 deUint32 rgb = step*levelNdx;
155 deUint32 colorA = 0xff000000 | rgb;
156 deUint32 colorB = 0xff000000 | ~rgb;
158 m_textures[1]->getRefTexture().allocLevel(levelNdx);
159 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
163 for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
169 // Clean up to save memory.
170 Texture2DFilteringCase::deinit();
175 void Texture2DFilteringCase::deinit (void)
177 for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
184 Texture2DFilteringCase::IterateResult Texture2DFilteringCase::iterate (void)
186 const glw::Functions& gl = m_renderCtx.getFunctions();
187 TestLog& log = m_testCtx.getLog();
188 const int defViewportWidth = 256;
189 const int defViewportHeight = 256;
190 RandomViewport viewport (m_renderCtx.getRenderTarget(), defViewportWidth, defViewportHeight, deStringHash(getName()));
191 tcu::Surface renderedFrame (viewport.width, viewport.height);
192 tcu::Surface referenceFrame (viewport.width, viewport.height);
193 const tcu::TextureFormat& texFmt = m_textures[0]->getRefTexture().getFormat();
194 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
195 ReferenceParams refParams (TEXTURETYPE_2D);
196 vector<float> texCoord;
198 // Accuracy measurements are off unless viewport size is 256x256
199 if (viewport.width < defViewportWidth || viewport.height < defViewportHeight)
200 throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
202 // Viewport is divided into 4 sections.
203 int leftWidth = viewport.width / 2;
204 int rightWidth = viewport.width - leftWidth;
205 int bottomHeight = viewport.height / 2;
206 int topHeight = viewport.height - bottomHeight;
211 gl.activeTexture(GL_TEXTURE0);
213 // Bind gradient texture and setup sampler parameters.
214 gl.bindTexture(GL_TEXTURE_2D, m_textures[curTexNdx]->getGLTexture());
215 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS);
216 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT);
217 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter);
218 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter);
220 // Setup params for reference.
221 refParams.sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
222 refParams.samplerType = getSamplerType(texFmt);
223 refParams.lodMode = LODMODE_EXACT;
224 refParams.colorBias = fmtInfo.lookupBias;
225 refParams.colorScale = fmtInfo.lookupScale;
227 // Bottom left: Minification
229 gl.viewport(viewport.x, viewport.y, leftWidth, bottomHeight);
231 computeQuadTexCoord2D(texCoord, tcu::Vec2(-4.0f, -4.5f), tcu::Vec2(4.0f, 2.5f));
233 m_renderer.renderQuad(0, &texCoord[0], refParams);
234 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, leftWidth, bottomHeight),
235 m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
238 // Bottom right: Magnification
240 gl.viewport(viewport.x+leftWidth, viewport.y, rightWidth, bottomHeight);
242 computeQuadTexCoord2D(texCoord, tcu::Vec2(-0.5f, 0.75f), tcu::Vec2(0.25f, 1.25f));
244 m_renderer.renderQuad(0, &texCoord[0], refParams);
245 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, 0, rightWidth, bottomHeight),
246 m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
249 if (m_textures.size() >= 2)
253 // Setup second texture.
254 gl.bindTexture(GL_TEXTURE_2D, m_textures[curTexNdx]->getGLTexture());
255 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS);
256 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT);
257 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter);
258 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter);
261 // Top left: Minification
262 // \note Minification is chosen so that 0.0 < lod <= 0.5. This way special minification threshold rule will be triggered.
264 gl.viewport(viewport.x, viewport.y+bottomHeight, leftWidth, topHeight);
268 float sRange = ((float)leftWidth * 1.2f) / (float)m_textures[curTexNdx]->getRefTexture().getWidth();
269 float tRange = ((float)topHeight * 1.1f) / (float)m_textures[curTexNdx]->getRefTexture().getHeight();
271 computeQuadTexCoord2D(texCoord, tcu::Vec2(sMin, tMin), tcu::Vec2(sMin+sRange, tMin+tRange));
273 m_renderer.renderQuad(0, &texCoord[0], refParams);
274 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, bottomHeight, leftWidth, topHeight),
275 m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
278 // Top right: Magnification
280 gl.viewport(viewport.x+leftWidth, viewport.y+bottomHeight, rightWidth, topHeight);
282 computeQuadTexCoord2D(texCoord, tcu::Vec2(-0.5f, 0.75f), tcu::Vec2(0.25f, 1.25f));
284 m_renderer.renderQuad(0, &texCoord[0], refParams);
285 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, bottomHeight, rightWidth, topHeight),
286 m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
290 glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
294 const int bestScoreDiff = 16;
295 const int worstScoreDiff = 3200;
297 int score = measureAccuracy(log, referenceFrame, renderedFrame, bestScoreDiff, worstScoreDiff);
298 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str());
304 class TextureCubeFilteringCase : public tcu::TestCase
307 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);
308 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);
309 ~TextureCubeFilteringCase (void);
313 IterateResult iterate (void);
316 TextureCubeFilteringCase (const TextureCubeFilteringCase& other);
317 TextureCubeFilteringCase& operator= (const TextureCubeFilteringCase& other);
319 glu::RenderContext& m_renderCtx;
320 const glu::ContextInfo& m_renderCtxInfo;
322 deUint32 m_minFilter;
323 deUint32 m_magFilter;
326 bool m_onlySampleFaceInterior; //!< If true, we avoid sampling anywhere near a face's edges.
328 deUint32 m_internalFormat;
332 std::vector<std::string> m_filenames;
334 std::vector<glu::TextureCube*> m_textures;
335 TextureRenderer m_renderer;
338 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)
339 : TestCase (testCtx, tcu::NODETYPE_ACCURACY, name, desc)
340 , m_renderCtx (renderCtx)
341 , m_renderCtxInfo (ctxInfo)
342 , m_minFilter (minFilter)
343 , m_magFilter (magFilter)
346 , m_onlySampleFaceInterior (onlySampleFaceInterior)
347 , m_internalFormat (internalFormat)
350 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
354 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)
355 : TestCase (testCtx, tcu::NODETYPE_ACCURACY, name, desc)
356 , m_renderCtx (renderCtx)
357 , m_renderCtxInfo (ctxInfo)
358 , m_minFilter (minFilter)
359 , m_magFilter (magFilter)
362 , m_onlySampleFaceInterior (onlySampleFaceInterior)
363 , m_internalFormat (GL_NONE)
366 , m_filenames (filenames)
367 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
371 TextureCubeFilteringCase::~TextureCubeFilteringCase (void)
376 void TextureCubeFilteringCase::init (void)
380 if (!m_filenames.empty())
382 m_textures.reserve(1);
383 m_textures.push_back(glu::TextureCube::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(), (int)m_filenames.size() / 6, m_filenames));
387 m_textures.reserve(2);
388 DE_ASSERT(m_width == m_height);
389 for (int ndx = 0; ndx < 2; ndx++)
390 m_textures.push_back(new glu::TextureCube(m_renderCtx, m_internalFormat, m_width));
392 const int numLevels = deLog2Floor32(de::max(m_width, m_height))+1;
393 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
394 tcu::Vec4 cBias = fmtInfo.valueMin;
395 tcu::Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin;
397 // Fill first with gradient texture.
398 static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] =
400 { tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x
401 { tcu::Vec4( 0.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x
402 { tcu::Vec4(-1.0f, 0.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y
403 { tcu::Vec4(-1.0f, -1.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y
404 { tcu::Vec4(-1.0f, -1.0f, -1.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z
405 { tcu::Vec4( 0.0f, 0.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) } // positive z
407 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
409 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
411 m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
412 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias);
416 // Fill second with grid texture.
417 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
419 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
421 deUint32 step = 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST);
422 deUint32 rgb = step*levelNdx*face;
423 deUint32 colorA = 0xff000000 | rgb;
424 deUint32 colorB = 0xff000000 | ~rgb;
426 m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
427 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
431 if (m_magFilter == GL_LINEAR || m_minFilter == GL_LINEAR || m_minFilter == GL_LINEAR_MIPMAP_NEAREST || m_minFilter == GL_LINEAR_MIPMAP_LINEAR)
433 // Using seamless linear cube map filtering - set all corner texels to the same color, because cube corner sampling in this case is not very well defined by the spec.
434 // \todo Probably should also do this for cases where textures are loaded from files.
436 for (int texNdx = 0; texNdx < (int)m_textures.size(); texNdx++)
438 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
440 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
442 static const tcu::Vec4 color(0.0f, 0.0f, 0.0f, 1.0f);
443 tcu::PixelBufferAccess access = m_textures[texNdx]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face);
445 access.setPixel(color, 0, 0);
446 access.setPixel(color, access.getWidth()-1, 0);
447 access.setPixel(color, 0, access.getHeight()-1);
448 access.setPixel(color, access.getWidth()-1, access.getHeight()-1);
455 for (std::vector<glu::TextureCube*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
459 catch (const std::exception&)
461 // Clean up to save memory.
462 TextureCubeFilteringCase::deinit();
467 void TextureCubeFilteringCase::deinit (void)
469 for (std::vector<glu::TextureCube*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
476 static void renderFaces (
477 const glw::Functions& gl,
478 const tcu::SurfaceAccess& dstRef,
479 const tcu::TextureCube& refTexture,
480 const ReferenceParams& params,
481 TextureRenderer& renderer,
486 const tcu::Vec2& bottomLeft,
487 const tcu::Vec2& topRight,
488 const tcu::Vec2& texCoordTopRightFactor)
490 DE_ASSERT(width == dstRef.getWidth() && height == dstRef.getHeight());
492 vector<float> texCoord;
494 DE_STATIC_ASSERT(tcu::CUBEFACE_LAST == 6);
495 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
497 bool isRightmost = (face == 2) || (face == 5);
498 bool isTop = face >= 3;
499 int curX = (face % 3) * (width / 3);
500 int curY = (face / 3) * (height / 2);
501 int curW = isRightmost ? (width-curX) : (width / 3);
502 int curH = isTop ? (height-curY) : (height / 2);
504 computeQuadTexCoordCube(texCoord, (tcu::CubeFace)face, bottomLeft, topRight);
507 // Move the top and right edges of the texture coord quad. This is useful when we want a cube edge visible.
508 int texCoordSRow = face == tcu::CUBEFACE_NEGATIVE_X || face == tcu::CUBEFACE_POSITIVE_X ? 2 : 0;
509 int texCoordTRow = face == tcu::CUBEFACE_NEGATIVE_Y || face == tcu::CUBEFACE_POSITIVE_Y ? 2 : 1;
510 texCoord[6 + texCoordSRow] *= texCoordTopRightFactor.x();
511 texCoord[9 + texCoordSRow] *= texCoordTopRightFactor.x();
512 texCoord[3 + texCoordTRow] *= texCoordTopRightFactor.y();
513 texCoord[9 + texCoordTRow] *= texCoordTopRightFactor.y();
516 gl.viewport(x+curX, y+curY, curW, curH);
518 renderer.renderQuad(0, &texCoord[0], params);
520 sampleTexture(tcu::SurfaceAccess(dstRef, curX, curY, curW, curH), refTexture, &texCoord[0], params);
523 GLU_EXPECT_NO_ERROR(gl.getError(), "Post render");
526 TextureCubeFilteringCase::IterateResult TextureCubeFilteringCase::iterate (void)
528 const glw::Functions& gl = m_renderCtx.getFunctions();
529 TestLog& log = m_testCtx.getLog();
530 const int cellSize = 28;
531 const int defViewportWidth = cellSize*6;
532 const int defViewportHeight = cellSize*4;
533 RandomViewport viewport (m_renderCtx.getRenderTarget(), cellSize*6, cellSize*4, deStringHash(getName()));
534 tcu::Surface renderedFrame (viewport.width, viewport.height);
535 tcu::Surface referenceFrame (viewport.width, viewport.height);
536 ReferenceParams sampleParams (TEXTURETYPE_CUBE);
537 const tcu::TextureFormat& texFmt = m_textures[0]->getRefTexture().getFormat();
538 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
540 // Accuracy measurements are off unless viewport size is exactly as expected.
541 if (getNodeType() == tcu::NODETYPE_ACCURACY && (viewport.width < defViewportWidth || viewport.height < defViewportHeight))
542 throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
544 // Viewport is divided into 4 sections.
545 int leftWidth = viewport.width / 2;
546 int rightWidth = viewport.width - leftWidth;
547 int bottomHeight = viewport.height / 2;
548 int topHeight = viewport.height - bottomHeight;
552 // Sampling parameters.
553 sampleParams.sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
554 sampleParams.sampler.seamlessCubeMap = true;
555 sampleParams.samplerType = getSamplerType(texFmt);
556 sampleParams.colorBias = fmtInfo.lookupBias;
557 sampleParams.colorScale = fmtInfo.lookupScale;
558 sampleParams.lodMode = LODMODE_EXACT;
561 gl.activeTexture(GL_TEXTURE0);
563 // Setup gradient texture.
564 gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textures[curTexNdx]->getGLTexture());
565 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS);
566 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT);
567 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter);
568 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter);
570 // Bottom left: Minification
572 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, leftWidth, bottomHeight),
573 m_textures[curTexNdx]->getRefTexture(), sampleParams,
575 viewport.x, viewport.y, leftWidth, bottomHeight,
576 m_onlySampleFaceInterior ? tcu::Vec2(-0.81f, -0.81f) : tcu::Vec2(-0.975f, -0.975f),
577 m_onlySampleFaceInterior ? tcu::Vec2( 0.8f, 0.8f) : tcu::Vec2( 0.975f, 0.975f),
578 !m_onlySampleFaceInterior ? tcu::Vec2(1.3f, 1.25f) : tcu::Vec2(1.0f, 1.0f));
580 // Bottom right: Magnification
582 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, 0, rightWidth, bottomHeight),
583 m_textures[curTexNdx]->getRefTexture(), sampleParams,
585 viewport.x+leftWidth, viewport.y, rightWidth, bottomHeight,
586 tcu::Vec2(0.5f, 0.65f), m_onlySampleFaceInterior ? tcu::Vec2(0.8f, 0.8f) : tcu::Vec2(0.975f, 0.975f),
587 !m_onlySampleFaceInterior ? tcu::Vec2(1.1f, 1.06f) : tcu::Vec2(1.0f, 1.0f));
589 if (m_textures.size() >= 2)
593 // Setup second texture.
594 gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textures[curTexNdx]->getGLTexture());
595 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS);
596 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT);
597 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter);
598 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter);
601 // Top left: Minification
603 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, bottomHeight, leftWidth, topHeight),
604 m_textures[curTexNdx]->getRefTexture(), sampleParams,
606 viewport.x, viewport.y+bottomHeight, leftWidth, topHeight,
607 m_onlySampleFaceInterior ? tcu::Vec2(-0.81f, -0.81f) : tcu::Vec2(-0.975f, -0.975f),
608 m_onlySampleFaceInterior ? tcu::Vec2( 0.8f, 0.8f) : tcu::Vec2( 0.975f, 0.975f),
609 !m_onlySampleFaceInterior ? tcu::Vec2(1.3f, 1.25f) : tcu::Vec2(1.0f, 1.0f));
611 // Top right: Magnification
613 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, bottomHeight, rightWidth, topHeight),
614 m_textures[curTexNdx]->getRefTexture(), sampleParams,
616 viewport.x+leftWidth, viewport.y+bottomHeight, rightWidth, topHeight,
617 tcu::Vec2(0.5f, -0.65f), m_onlySampleFaceInterior ? tcu::Vec2(0.8f, -0.8f) : tcu::Vec2(0.975f, -0.975f),
618 !m_onlySampleFaceInterior ? tcu::Vec2(1.1f, 1.06f) : tcu::Vec2(1.0f, 1.0f));
621 glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
625 const int bestScoreDiff = 16;
626 const int worstScoreDiff = 10000;
628 int score = measureAccuracy(log, referenceFrame, renderedFrame, bestScoreDiff, worstScoreDiff);
629 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str());
635 TextureFilteringTests::TextureFilteringTests (Context& context)
636 : TestCaseGroup(context, "filter", "Texture Filtering Accuracy Tests")
640 TextureFilteringTests::~TextureFilteringTests (void)
644 void TextureFilteringTests::init (void)
646 tcu::TestCaseGroup* group2D = new tcu::TestCaseGroup(m_testCtx, "2d", "2D Texture Filtering");
647 tcu::TestCaseGroup* groupCube = new tcu::TestCaseGroup(m_testCtx, "cube", "Cube Map Filtering");
657 { "clamp", GL_CLAMP_TO_EDGE },
658 { "repeat", GL_REPEAT },
659 { "mirror", GL_MIRRORED_REPEAT }
668 { "nearest", GL_NEAREST },
669 { "linear", GL_LINEAR },
670 { "nearest_mipmap_nearest", GL_NEAREST_MIPMAP_NEAREST },
671 { "linear_mipmap_nearest", GL_LINEAR_MIPMAP_NEAREST },
672 { "nearest_mipmap_linear", GL_NEAREST_MIPMAP_LINEAR },
673 { "linear_mipmap_linear", GL_LINEAR_MIPMAP_LINEAR }
682 { "nearest", GL_NEAREST },
683 { "linear", GL_LINEAR }
714 { "rgba8", GL_RGBA8 }
717 #define FOR_EACH(ITERATOR, ARRAY, BODY) \
718 for (int ITERATOR = 0; ITERATOR < DE_LENGTH_OF_ARRAY(ARRAY); ITERATOR++) \
722 FOR_EACH(minFilter, minFilterModes,
723 FOR_EACH(magFilter, magFilterModes,
724 FOR_EACH(wrapMode, wrapModes,
725 FOR_EACH(format, formats,
726 FOR_EACH(size, sizes2D,
728 string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name + "_" + formats[format].name + string("_") + sizes2D[size].name;
730 group2D->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
732 minFilterModes[minFilter].mode,
733 magFilterModes[magFilter].mode,
734 wrapModes[wrapMode].mode,
735 wrapModes[wrapMode].mode,
736 formats[format].format,
737 sizes2D[size].width, sizes2D[size].height));
741 FOR_EACH(minFilter, minFilterModes,
742 FOR_EACH(magFilter, magFilterModes,
743 FOR_EACH(wrapMode, wrapModes,
744 FOR_EACH(format, formats,
745 FOR_EACH(size, sizesCube,
747 string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name + "_" + formats[format].name + string("_") + sizesCube[size].name;
749 groupCube->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
751 minFilterModes[minFilter].mode,
752 magFilterModes[magFilter].mode,
753 wrapModes[wrapMode].mode,
754 wrapModes[wrapMode].mode,
756 formats[format].format,
757 sizesCube[size].width, sizesCube[size].height));