1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Texture filtering accuracy tests.
22 *//*--------------------------------------------------------------------*/
23
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"
32 #include "deString.h"
33
34 #include "glwFunctions.hpp"
35 #include "glwEnums.hpp"
36
37 namespace deqp
38 {
39 namespace gles3
40 {
41 namespace Accuracy
42 {
43
44 using std::vector;
45 using std::string;
46 using tcu::TestLog;
47 using namespace gls::TextureTestUtil;
48 using namespace glu::TextureTestUtil;
49
50 class Texture2DFilteringCase : public tcu::TestCase
51 {
52 public:
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);
56
57 void init (void);
58 void deinit (void);
59 IterateResult iterate (void);
60
61 private:
62 Texture2DFilteringCase (const Texture2DFilteringCase& other);
63 Texture2DFilteringCase& operator= (const Texture2DFilteringCase& other);
64
65 glu::RenderContext& m_renderCtx;
66 const glu::ContextInfo& m_renderCtxInfo;
67
68 deUint32 m_minFilter;
69 deUint32 m_magFilter;
70 deUint32 m_wrapS;
71 deUint32 m_wrapT;
72
73 deUint32 m_internalFormat;
74 int m_width;
75 int m_height;
76
77 std::vector<std::string> m_filenames;
78
79 std::vector<glu::Texture2D*> m_textures;
80 TextureRenderer m_renderer;
81 };
82
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)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)
89 , m_wrapS (wrapS)
90 , m_wrapT (wrapT)
91 , m_internalFormat (internalFormat)
92 , m_width (width)
93 , m_height (height)
94 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
95 {
96 }
97
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)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)
104 , m_wrapS (wrapS)
105 , m_wrapT (wrapT)
106 , m_internalFormat (GL_NONE)
107 , m_width (0)
108 , m_height (0)
109 , m_filenames (filenames)
110 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_HIGHP)
111 {
112 }
113
~Texture2DFilteringCase(void)114 Texture2DFilteringCase::~Texture2DFilteringCase (void)
115 {
116 deinit();
117 }
118
init(void)119 void Texture2DFilteringCase::init (void)
120 {
121 try
122 {
123 if (!m_filenames.empty())
124 {
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));
127 }
128 else
129 {
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));
134
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;
139
140 // Fill first gradient texture.
141 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
142 {
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;
145
146 m_textures[0]->getRefTexture().allocLevel(levelNdx);
147 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax);
148 }
149
150 // Fill second with grid texture.
151 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
152 {
153 deUint32 step = 0x00ffffff / numLevels;
154 deUint32 rgb = step*levelNdx;
155 deUint32 colorA = 0xff000000 | rgb;
156 deUint32 colorB = 0xff000000 | ~rgb;
157
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);
160 }
161
162 // Upload.
163 for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
164 (*i)->upload();
165 }
166 }
167 catch (...)
168 {
169 // Clean up to save memory.
170 Texture2DFilteringCase::deinit();
171 throw;
172 }
173 }
174
deinit(void)175 void Texture2DFilteringCase::deinit (void)
176 {
177 for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
178 delete *i;
179 m_textures.clear();
180
181 m_renderer.clear();
182 }
183
iterate(void)184 Texture2DFilteringCase::IterateResult Texture2DFilteringCase::iterate (void)
185 {
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;
197
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__);
201
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;
207
208 int curTexNdx = 0;
209
210 // Use unit 0.
211 gl.activeTexture(GL_TEXTURE0);
212
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);
219
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;
226
227 // Bottom left: Minification
228 {
229 gl.viewport(viewport.x, viewport.y, leftWidth, bottomHeight);
230
231 computeQuadTexCoord2D(texCoord, tcu::Vec2(-4.0f, -4.5f), tcu::Vec2(4.0f, 2.5f));
232
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);
236 }
237
238 // Bottom right: Magnification
239 {
240 gl.viewport(viewport.x+leftWidth, viewport.y, rightWidth, bottomHeight);
241
242 computeQuadTexCoord2D(texCoord, tcu::Vec2(-0.5f, 0.75f), tcu::Vec2(0.25f, 1.25f));
243
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);
247 }
248
249 if (m_textures.size() >= 2)
250 {
251 curTexNdx += 1;
252
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);
259 }
260
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.
263 {
264 gl.viewport(viewport.x, viewport.y+bottomHeight, leftWidth, topHeight);
265
266 float sMin = -0.5f;
267 float tMin = -0.2f;
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();
270
271 computeQuadTexCoord2D(texCoord, tcu::Vec2(sMin, tMin), tcu::Vec2(sMin+sRange, tMin+tRange));
272
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);
276 }
277
278 // Top right: Magnification
279 {
280 gl.viewport(viewport.x+leftWidth, viewport.y+bottomHeight, rightWidth, topHeight);
281
282 computeQuadTexCoord2D(texCoord, tcu::Vec2(-0.5f, 0.75f), tcu::Vec2(0.25f, 1.25f));
283
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);
287 }
288
289 // Read result.
290 glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
291
292 // Compare and log.
293 {
294 const int bestScoreDiff = 16;
295 const int worstScoreDiff = 3200;
296
297 int score = measureAccuracy(log, referenceFrame, renderedFrame, bestScoreDiff, worstScoreDiff);
298 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str());
299 }
300
301 return STOP;
302 }
303
304 class TextureCubeFilteringCase : public tcu::TestCase
305 {
306 public:
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);
310
311 void init (void);
312 void deinit (void);
313 IterateResult iterate (void);
314
315 private:
316 TextureCubeFilteringCase (const TextureCubeFilteringCase& other);
317 TextureCubeFilteringCase& operator= (const TextureCubeFilteringCase& other);
318
319 glu::RenderContext& m_renderCtx;
320 const glu::ContextInfo& m_renderCtxInfo;
321
322 deUint32 m_minFilter;
323 deUint32 m_magFilter;
324 deUint32 m_wrapS;
325 deUint32 m_wrapT;
326 bool m_onlySampleFaceInterior; //!< If true, we avoid sampling anywhere near a face's edges.
327
328 deUint32 m_internalFormat;
329 int m_width;
330 int m_height;
331
332 std::vector<std::string> m_filenames;
333
334 std::vector<glu::TextureCube*> m_textures;
335 TextureRenderer m_renderer;
336 };
337
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)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)
344 , m_wrapS (wrapS)
345 , m_wrapT (wrapT)
346 , m_onlySampleFaceInterior (onlySampleFaceInterior)
347 , m_internalFormat (internalFormat)
348 , m_width (width)
349 , m_height (height)
350 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
351 {
352 }
353
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)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)
360 , m_wrapS (wrapS)
361 , m_wrapT (wrapT)
362 , m_onlySampleFaceInterior (onlySampleFaceInterior)
363 , m_internalFormat (GL_NONE)
364 , m_width (0)
365 , m_height (0)
366 , m_filenames (filenames)
367 , m_renderer (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
368 {
369 }
370
~TextureCubeFilteringCase(void)371 TextureCubeFilteringCase::~TextureCubeFilteringCase (void)
372 {
373 deinit();
374 }
375
init(void)376 void TextureCubeFilteringCase::init (void)
377 {
378 try
379 {
380 if (!m_filenames.empty())
381 {
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));
384 }
385 else
386 {
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));
391
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;
396
397 // Fill first with gradient texture.
398 static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] =
399 {
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
406 };
407 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
408 {
409 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
410 {
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);
413 }
414 }
415
416 // Fill second with grid texture.
417 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
418 {
419 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
420 {
421 deUint32 step = 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST);
422 deUint32 rgb = step*levelNdx*face;
423 deUint32 colorA = 0xff000000 | rgb;
424 deUint32 colorB = 0xff000000 | ~rgb;
425
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);
428 }
429 }
430
431 if (m_magFilter == GL_LINEAR || m_minFilter == GL_LINEAR || m_minFilter == GL_LINEAR_MIPMAP_NEAREST || m_minFilter == GL_LINEAR_MIPMAP_LINEAR)
432 {
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.
435
436 for (int texNdx = 0; texNdx < (int)m_textures.size(); texNdx++)
437 {
438 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
439 {
440 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
441 {
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);
444
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);
449 }
450 }
451 }
452 }
453
454 // Upload.
455 for (std::vector<glu::TextureCube*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
456 (*i)->upload();
457 }
458 }
459 catch (const std::exception&)
460 {
461 // Clean up to save memory.
462 TextureCubeFilteringCase::deinit();
463 throw;
464 }
465 }
466
deinit(void)467 void TextureCubeFilteringCase::deinit (void)
468 {
469 for (std::vector<glu::TextureCube*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
470 delete *i;
471 m_textures.clear();
472
473 m_renderer.clear();
474 }
475
renderFaces(const glw::Functions & gl,const tcu::SurfaceAccess & dstRef,const tcu::TextureCube & refTexture,const ReferenceParams & params,TextureRenderer & renderer,int x,int y,int width,int height,const tcu::Vec2 & bottomLeft,const tcu::Vec2 & topRight,const tcu::Vec2 & texCoordTopRightFactor)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,
482 int x,
483 int y,
484 int width,
485 int height,
486 const tcu::Vec2& bottomLeft,
487 const tcu::Vec2& topRight,
488 const tcu::Vec2& texCoordTopRightFactor)
489 {
490 DE_ASSERT(width == dstRef.getWidth() && height == dstRef.getHeight());
491
492 vector<float> texCoord;
493
494 DE_STATIC_ASSERT(tcu::CUBEFACE_LAST == 6);
495 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
496 {
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);
503
504 computeQuadTexCoordCube(texCoord, (tcu::CubeFace)face, bottomLeft, topRight);
505
506 {
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();
514 }
515
516 gl.viewport(x+curX, y+curY, curW, curH);
517
518 renderer.renderQuad(0, &texCoord[0], params);
519
520 sampleTexture(tcu::SurfaceAccess(dstRef, curX, curY, curW, curH), refTexture, &texCoord[0], params);
521 }
522
523 GLU_EXPECT_NO_ERROR(gl.getError(), "Post render");
524 }
525
iterate(void)526 TextureCubeFilteringCase::IterateResult TextureCubeFilteringCase::iterate (void)
527 {
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);
539
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__);
543
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;
549
550 int curTexNdx = 0;
551
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;
559
560 // Use unit 0.
561 gl.activeTexture(GL_TEXTURE0);
562
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);
569
570 // Bottom left: Minification
571 renderFaces(gl,
572 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, leftWidth, bottomHeight),
573 m_textures[curTexNdx]->getRefTexture(), sampleParams,
574 m_renderer,
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));
579
580 // Bottom right: Magnification
581 renderFaces(gl,
582 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, 0, rightWidth, bottomHeight),
583 m_textures[curTexNdx]->getRefTexture(), sampleParams,
584 m_renderer,
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));
588
589 if (m_textures.size() >= 2)
590 {
591 curTexNdx += 1;
592
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);
599 }
600
601 // Top left: Minification
602 renderFaces(gl,
603 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, bottomHeight, leftWidth, topHeight),
604 m_textures[curTexNdx]->getRefTexture(), sampleParams,
605 m_renderer,
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));
610
611 // Top right: Magnification
612 renderFaces(gl,
613 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, bottomHeight, rightWidth, topHeight),
614 m_textures[curTexNdx]->getRefTexture(), sampleParams,
615 m_renderer,
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));
619
620 // Read result.
621 glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
622
623 // Compare and log.
624 {
625 const int bestScoreDiff = 16;
626 const int worstScoreDiff = 10000;
627
628 int score = measureAccuracy(log, referenceFrame, renderedFrame, bestScoreDiff, worstScoreDiff);
629 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str());
630 }
631
632 return STOP;
633 }
634
TextureFilteringTests(Context & context)635 TextureFilteringTests::TextureFilteringTests (Context& context)
636 : TestCaseGroup(context, "filter", "Texture Filtering Accuracy Tests")
637 {
638 }
639
~TextureFilteringTests(void)640 TextureFilteringTests::~TextureFilteringTests (void)
641 {
642 }
643
init(void)644 void TextureFilteringTests::init (void)
645 {
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");
648 addChild(group2D);
649 addChild(groupCube);
650
651 static const struct
652 {
653 const char* name;
654 deUint32 mode;
655 } wrapModes[] =
656 {
657 { "clamp", GL_CLAMP_TO_EDGE },
658 { "repeat", GL_REPEAT },
659 { "mirror", GL_MIRRORED_REPEAT }
660 };
661
662 static const struct
663 {
664 const char* name;
665 deUint32 mode;
666 } minFilterModes[] =
667 {
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 }
674 };
675
676 static const struct
677 {
678 const char* name;
679 deUint32 mode;
680 } magFilterModes[] =
681 {
682 { "nearest", GL_NEAREST },
683 { "linear", GL_LINEAR }
684 };
685
686 static const struct
687 {
688 const char* name;
689 int width;
690 int height;
691 } sizes2D[] =
692 {
693 { "pot", 32, 64 },
694 { "npot", 31, 55 }
695 };
696
697 static const struct
698 {
699 const char* name;
700 int width;
701 int height;
702 } sizesCube[] =
703 {
704 { "pot", 64, 64 },
705 { "npot", 63, 63 }
706 };
707
708 static const struct
709 {
710 const char* name;
711 deUint32 format;
712 } formats[] =
713 {
714 { "rgba8", GL_RGBA8 }
715 };
716
717 #define FOR_EACH(ITERATOR, ARRAY, BODY) \
718 for (int ITERATOR = 0; ITERATOR < DE_LENGTH_OF_ARRAY(ARRAY); ITERATOR++) \
719 BODY
720
721 // 2D cases.
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,
727 {
728 string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name + "_" + formats[format].name + string("_") + sizes2D[size].name;
729
730 group2D->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
731 name.c_str(), "",
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));
738 })))));
739
740 // Cubemap cases.
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,
746 {
747 string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name + "_" + formats[format].name + string("_") + sizesCube[size].name;
748
749 groupCube->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
750 name.c_str(), "",
751 minFilterModes[minFilter].mode,
752 magFilterModes[magFilter].mode,
753 wrapModes[wrapMode].mode,
754 wrapModes[wrapMode].mode,
755 false,
756 formats[format].format,
757 sizesCube[size].width, sizesCube[size].height));
758 })))));
759 }
760
761 } // Accuracy
762 } // gles3
763 } // deqp
764