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::string;
45 using std::vector;
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,
54 const char *name, const char *desc, uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
55 uint32_t wrapT, uint32_t internalFormat, int width, int height);
56 Texture2DFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const glu::ContextInfo &ctxInfo,
57 const char *name, const char *desc, uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
58 uint32_t wrapT, const std::vector<std::string> &filenames);
59 ~Texture2DFilteringCase(void);
60
61 void init(void);
62 void deinit(void);
63 IterateResult iterate(void);
64
65 private:
66 Texture2DFilteringCase(const Texture2DFilteringCase &other);
67 Texture2DFilteringCase &operator=(const Texture2DFilteringCase &other);
68
69 glu::RenderContext &m_renderCtx;
70 const glu::ContextInfo &m_renderCtxInfo;
71
72 uint32_t m_minFilter;
73 uint32_t m_magFilter;
74 uint32_t m_wrapS;
75 uint32_t m_wrapT;
76
77 uint32_t m_internalFormat;
78 int m_width;
79 int m_height;
80
81 std::vector<std::string> m_filenames;
82
83 std::vector<glu::Texture2D *> m_textures;
84 TextureRenderer m_renderer;
85 };
86
Texture2DFilteringCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const glu::ContextInfo & ctxInfo,const char * name,const char * desc,uint32_t minFilter,uint32_t magFilter,uint32_t wrapS,uint32_t wrapT,uint32_t internalFormat,int width,int height)87 Texture2DFilteringCase::Texture2DFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
88 const glu::ContextInfo &ctxInfo, const char *name, const char *desc,
89 uint32_t minFilter, uint32_t magFilter, uint32_t wrapS, uint32_t wrapT,
90 uint32_t internalFormat, int width, int height)
91 : TestCase(testCtx, tcu::NODETYPE_ACCURACY, name, desc)
92 , m_renderCtx(renderCtx)
93 , m_renderCtxInfo(ctxInfo)
94 , m_minFilter(minFilter)
95 , m_magFilter(magFilter)
96 , m_wrapS(wrapS)
97 , m_wrapT(wrapT)
98 , m_internalFormat(internalFormat)
99 , m_width(width)
100 , m_height(height)
101 , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
102 {
103 }
104
Texture2DFilteringCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const glu::ContextInfo & ctxInfo,const char * name,const char * desc,uint32_t minFilter,uint32_t magFilter,uint32_t wrapS,uint32_t wrapT,const std::vector<std::string> & filenames)105 Texture2DFilteringCase::Texture2DFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
106 const glu::ContextInfo &ctxInfo, const char *name, const char *desc,
107 uint32_t minFilter, uint32_t magFilter, uint32_t wrapS, uint32_t wrapT,
108 const std::vector<std::string> &filenames)
109 : TestCase(testCtx, tcu::NODETYPE_ACCURACY, name, desc)
110 , m_renderCtx(renderCtx)
111 , m_renderCtxInfo(ctxInfo)
112 , m_minFilter(minFilter)
113 , m_magFilter(magFilter)
114 , m_wrapS(wrapS)
115 , m_wrapT(wrapT)
116 , m_internalFormat(GL_NONE)
117 , m_width(0)
118 , m_height(0)
119 , m_filenames(filenames)
120 , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_HIGHP)
121 {
122 }
123
~Texture2DFilteringCase(void)124 Texture2DFilteringCase::~Texture2DFilteringCase(void)
125 {
126 deinit();
127 }
128
init(void)129 void Texture2DFilteringCase::init(void)
130 {
131 try
132 {
133 if (!m_filenames.empty())
134 {
135 m_textures.reserve(1);
136 m_textures.push_back(glu::Texture2D::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(),
137 (int)m_filenames.size(), m_filenames));
138 }
139 else
140 {
141 // Create 2 textures.
142 m_textures.reserve(2);
143 for (int ndx = 0; ndx < 2; ndx++)
144 m_textures.push_back(new glu::Texture2D(m_renderCtx, m_internalFormat, m_width, m_height));
145
146 const int numLevels = deLog2Floor32(de::max(m_width, m_height)) + 1;
147 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
148 tcu::Vec4 cBias = fmtInfo.valueMin;
149 tcu::Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
150
151 // Fill first gradient texture.
152 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
153 {
154 tcu::Vec4 gMin = tcu::Vec4(-0.5f, -0.5f, -0.5f, 2.0f) * cScale + cBias;
155 tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) * cScale + cBias;
156
157 m_textures[0]->getRefTexture().allocLevel(levelNdx);
158 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax);
159 }
160
161 // Fill second with grid texture.
162 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
163 {
164 uint32_t step = 0x00ffffff / numLevels;
165 uint32_t rgb = step * levelNdx;
166 uint32_t colorA = 0xff000000 | rgb;
167 uint32_t colorB = 0xff000000 | ~rgb;
168
169 m_textures[1]->getRefTexture().allocLevel(levelNdx);
170 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4,
171 tcu::RGBA(colorA).toVec() * cScale + cBias,
172 tcu::RGBA(colorB).toVec() * cScale + cBias);
173 }
174
175 // Upload.
176 for (std::vector<glu::Texture2D *>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
177 (*i)->upload();
178 }
179 }
180 catch (...)
181 {
182 // Clean up to save memory.
183 Texture2DFilteringCase::deinit();
184 throw;
185 }
186 }
187
deinit(void)188 void Texture2DFilteringCase::deinit(void)
189 {
190 for (std::vector<glu::Texture2D *>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
191 delete *i;
192 m_textures.clear();
193
194 m_renderer.clear();
195 }
196
iterate(void)197 Texture2DFilteringCase::IterateResult Texture2DFilteringCase::iterate(void)
198 {
199 const glw::Functions &gl = m_renderCtx.getFunctions();
200 TestLog &log = m_testCtx.getLog();
201 const int defViewportWidth = 256;
202 const int defViewportHeight = 256;
203 RandomViewport viewport(m_renderCtx.getRenderTarget(), defViewportWidth, defViewportHeight,
204 deStringHash(getName()));
205 tcu::Surface renderedFrame(viewport.width, viewport.height);
206 tcu::Surface referenceFrame(viewport.width, viewport.height);
207 const tcu::TextureFormat &texFmt = m_textures[0]->getRefTexture().getFormat();
208 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
209 ReferenceParams refParams(TEXTURETYPE_2D);
210 vector<float> texCoord;
211
212 // Accuracy measurements are off unless viewport size is 256x256
213 if (viewport.width < defViewportWidth || viewport.height < defViewportHeight)
214 throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
215
216 // Viewport is divided into 4 sections.
217 int leftWidth = viewport.width / 2;
218 int rightWidth = viewport.width - leftWidth;
219 int bottomHeight = viewport.height / 2;
220 int topHeight = viewport.height - bottomHeight;
221
222 int curTexNdx = 0;
223
224 // Use unit 0.
225 gl.activeTexture(GL_TEXTURE0);
226
227 // Bind gradient texture and setup sampler parameters.
228 gl.bindTexture(GL_TEXTURE_2D, m_textures[curTexNdx]->getGLTexture());
229 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS);
230 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT);
231 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter);
232 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter);
233
234 // Setup params for reference.
235 refParams.sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
236 refParams.samplerType = getSamplerType(texFmt);
237 refParams.lodMode = LODMODE_EXACT;
238 refParams.colorBias = fmtInfo.lookupBias;
239 refParams.colorScale = fmtInfo.lookupScale;
240
241 // Bottom left: Minification
242 {
243 gl.viewport(viewport.x, viewport.y, leftWidth, bottomHeight);
244
245 computeQuadTexCoord2D(texCoord, tcu::Vec2(-4.0f, -4.5f), tcu::Vec2(4.0f, 2.5f));
246
247 m_renderer.renderQuad(0, &texCoord[0], refParams);
248 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0,
249 leftWidth, bottomHeight),
250 m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
251 }
252
253 // Bottom right: Magnification
254 {
255 gl.viewport(viewport.x + leftWidth, viewport.y, rightWidth, bottomHeight);
256
257 computeQuadTexCoord2D(texCoord, tcu::Vec2(-0.5f, 0.75f), tcu::Vec2(0.25f, 1.25f));
258
259 m_renderer.renderQuad(0, &texCoord[0], refParams);
260 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, 0,
261 rightWidth, bottomHeight),
262 m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
263 }
264
265 if (m_textures.size() >= 2)
266 {
267 curTexNdx += 1;
268
269 // Setup second texture.
270 gl.bindTexture(GL_TEXTURE_2D, m_textures[curTexNdx]->getGLTexture());
271 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS);
272 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT);
273 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter);
274 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter);
275 }
276
277 // Top left: Minification
278 // \note Minification is chosen so that 0.0 < lod <= 0.5. This way special minification threshold rule will be triggered.
279 {
280 gl.viewport(viewport.x, viewport.y + bottomHeight, leftWidth, topHeight);
281
282 float sMin = -0.5f;
283 float tMin = -0.2f;
284 float sRange = ((float)leftWidth * 1.2f) / (float)m_textures[curTexNdx]->getRefTexture().getWidth();
285 float tRange = ((float)topHeight * 1.1f) / (float)m_textures[curTexNdx]->getRefTexture().getHeight();
286
287 computeQuadTexCoord2D(texCoord, tcu::Vec2(sMin, tMin), tcu::Vec2(sMin + sRange, tMin + tRange));
288
289 m_renderer.renderQuad(0, &texCoord[0], refParams);
290 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0,
291 bottomHeight, leftWidth, topHeight),
292 m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
293 }
294
295 // Top right: Magnification
296 {
297 gl.viewport(viewport.x + leftWidth, viewport.y + bottomHeight, rightWidth, topHeight);
298
299 computeQuadTexCoord2D(texCoord, tcu::Vec2(-0.5f, 0.75f), tcu::Vec2(0.25f, 1.25f));
300
301 m_renderer.renderQuad(0, &texCoord[0], refParams);
302 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth,
303 bottomHeight, rightWidth, topHeight),
304 m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
305 }
306
307 // Read result.
308 glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
309
310 // Compare and log.
311 {
312 const int bestScoreDiff = 16;
313 const int worstScoreDiff = 3200;
314
315 int score = measureAccuracy(log, referenceFrame, renderedFrame, bestScoreDiff, worstScoreDiff);
316 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str());
317 }
318
319 return STOP;
320 }
321
322 class TextureCubeFilteringCase : public tcu::TestCase
323 {
324 public:
325 TextureCubeFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const glu::ContextInfo &ctxInfo,
326 const char *name, const char *desc, uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
327 uint32_t wrapT, bool onlySampleFaceInterior, uint32_t internalFormat, int width,
328 int height);
329 TextureCubeFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const glu::ContextInfo &ctxInfo,
330 const char *name, const char *desc, uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
331 uint32_t wrapT, bool onlySampleFaceInterior, const std::vector<std::string> &filenames);
332 ~TextureCubeFilteringCase(void);
333
334 void init(void);
335 void deinit(void);
336 IterateResult iterate(void);
337
338 private:
339 TextureCubeFilteringCase(const TextureCubeFilteringCase &other);
340 TextureCubeFilteringCase &operator=(const TextureCubeFilteringCase &other);
341
342 glu::RenderContext &m_renderCtx;
343 const glu::ContextInfo &m_renderCtxInfo;
344
345 uint32_t m_minFilter;
346 uint32_t m_magFilter;
347 uint32_t m_wrapS;
348 uint32_t m_wrapT;
349 bool m_onlySampleFaceInterior; //!< If true, we avoid sampling anywhere near a face's edges.
350
351 uint32_t m_internalFormat;
352 int m_width;
353 int m_height;
354
355 std::vector<std::string> m_filenames;
356
357 std::vector<glu::TextureCube *> m_textures;
358 TextureRenderer m_renderer;
359 };
360
TextureCubeFilteringCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const glu::ContextInfo & ctxInfo,const char * name,const char * desc,uint32_t minFilter,uint32_t magFilter,uint32_t wrapS,uint32_t wrapT,bool onlySampleFaceInterior,uint32_t internalFormat,int width,int height)361 TextureCubeFilteringCase::TextureCubeFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
362 const glu::ContextInfo &ctxInfo, const char *name, const char *desc,
363 uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
364 uint32_t wrapT, bool onlySampleFaceInterior, uint32_t internalFormat,
365 int width, int height)
366 : TestCase(testCtx, tcu::NODETYPE_ACCURACY, name, desc)
367 , m_renderCtx(renderCtx)
368 , m_renderCtxInfo(ctxInfo)
369 , m_minFilter(minFilter)
370 , m_magFilter(magFilter)
371 , m_wrapS(wrapS)
372 , m_wrapT(wrapT)
373 , m_onlySampleFaceInterior(onlySampleFaceInterior)
374 , m_internalFormat(internalFormat)
375 , m_width(width)
376 , m_height(height)
377 , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
378 {
379 }
380
TextureCubeFilteringCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const glu::ContextInfo & ctxInfo,const char * name,const char * desc,uint32_t minFilter,uint32_t magFilter,uint32_t wrapS,uint32_t wrapT,bool onlySampleFaceInterior,const std::vector<std::string> & filenames)381 TextureCubeFilteringCase::TextureCubeFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
382 const glu::ContextInfo &ctxInfo, const char *name, const char *desc,
383 uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
384 uint32_t wrapT, bool onlySampleFaceInterior,
385 const std::vector<std::string> &filenames)
386 : TestCase(testCtx, tcu::NODETYPE_ACCURACY, name, desc)
387 , m_renderCtx(renderCtx)
388 , m_renderCtxInfo(ctxInfo)
389 , m_minFilter(minFilter)
390 , m_magFilter(magFilter)
391 , m_wrapS(wrapS)
392 , m_wrapT(wrapT)
393 , m_onlySampleFaceInterior(onlySampleFaceInterior)
394 , m_internalFormat(GL_NONE)
395 , m_width(0)
396 , m_height(0)
397 , m_filenames(filenames)
398 , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
399 {
400 }
401
~TextureCubeFilteringCase(void)402 TextureCubeFilteringCase::~TextureCubeFilteringCase(void)
403 {
404 deinit();
405 }
406
init(void)407 void TextureCubeFilteringCase::init(void)
408 {
409 try
410 {
411 if (!m_filenames.empty())
412 {
413 m_textures.reserve(1);
414 m_textures.push_back(glu::TextureCube::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(),
415 (int)m_filenames.size() / 6, m_filenames));
416 }
417 else
418 {
419 m_textures.reserve(2);
420 DE_ASSERT(m_width == m_height);
421 for (int ndx = 0; ndx < 2; ndx++)
422 m_textures.push_back(new glu::TextureCube(m_renderCtx, m_internalFormat, m_width));
423
424 const int numLevels = deLog2Floor32(de::max(m_width, m_height)) + 1;
425 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
426 tcu::Vec4 cBias = fmtInfo.valueMin;
427 tcu::Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
428
429 // Fill first with gradient texture.
430 static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] = {
431 {tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // negative x
432 {tcu::Vec4(0.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // positive x
433 {tcu::Vec4(-1.0f, 0.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // negative y
434 {tcu::Vec4(-1.0f, -1.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // positive y
435 {tcu::Vec4(-1.0f, -1.0f, -1.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f)}, // negative z
436 {tcu::Vec4(0.0f, 0.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)} // positive z
437 };
438 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
439 {
440 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
441 {
442 m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
443 tcu::fillWithComponentGradients(
444 m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face),
445 gradients[face][0] * cScale + cBias, gradients[face][1] * cScale + cBias);
446 }
447 }
448
449 // Fill second with grid texture.
450 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
451 {
452 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
453 {
454 uint32_t step = 0x00ffffff / (numLevels * tcu::CUBEFACE_LAST);
455 uint32_t rgb = step * levelNdx * face;
456 uint32_t colorA = 0xff000000 | rgb;
457 uint32_t colorB = 0xff000000 | ~rgb;
458
459 m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
460 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4,
461 tcu::RGBA(colorA).toVec() * cScale + cBias,
462 tcu::RGBA(colorB).toVec() * cScale + cBias);
463 }
464 }
465
466 if (m_magFilter == GL_LINEAR || m_minFilter == GL_LINEAR || m_minFilter == GL_LINEAR_MIPMAP_NEAREST ||
467 m_minFilter == GL_LINEAR_MIPMAP_LINEAR)
468 {
469 // 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.
470 // \todo Probably should also do this for cases where textures are loaded from files.
471
472 for (int texNdx = 0; texNdx < (int)m_textures.size(); texNdx++)
473 {
474 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
475 {
476 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
477 {
478 static const tcu::Vec4 color(0.0f, 0.0f, 0.0f, 1.0f);
479 tcu::PixelBufferAccess access =
480 m_textures[texNdx]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face);
481
482 access.setPixel(color, 0, 0);
483 access.setPixel(color, access.getWidth() - 1, 0);
484 access.setPixel(color, 0, access.getHeight() - 1);
485 access.setPixel(color, access.getWidth() - 1, access.getHeight() - 1);
486 }
487 }
488 }
489 }
490
491 // Upload.
492 for (std::vector<glu::TextureCube *>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
493 (*i)->upload();
494 }
495 }
496 catch (const std::exception &)
497 {
498 // Clean up to save memory.
499 TextureCubeFilteringCase::deinit();
500 throw;
501 }
502 }
503
deinit(void)504 void TextureCubeFilteringCase::deinit(void)
505 {
506 for (std::vector<glu::TextureCube *>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
507 delete *i;
508 m_textures.clear();
509
510 m_renderer.clear();
511 }
512
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)513 static void renderFaces(const glw::Functions &gl, const tcu::SurfaceAccess &dstRef, const tcu::TextureCube &refTexture,
514 const ReferenceParams ¶ms, TextureRenderer &renderer, int x, int y, int width, int height,
515 const tcu::Vec2 &bottomLeft, const tcu::Vec2 &topRight, const tcu::Vec2 &texCoordTopRightFactor)
516 {
517 DE_ASSERT(width == dstRef.getWidth() && height == dstRef.getHeight());
518
519 vector<float> texCoord;
520
521 DE_STATIC_ASSERT(tcu::CUBEFACE_LAST == 6);
522 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
523 {
524 bool isRightmost = (face == 2) || (face == 5);
525 bool isTop = face >= 3;
526 int curX = (face % 3) * (width / 3);
527 int curY = (face / 3) * (height / 2);
528 int curW = isRightmost ? (width - curX) : (width / 3);
529 int curH = isTop ? (height - curY) : (height / 2);
530
531 computeQuadTexCoordCube(texCoord, (tcu::CubeFace)face, bottomLeft, topRight);
532
533 {
534 // Move the top and right edges of the texture coord quad. This is useful when we want a cube edge visible.
535 int texCoordSRow = face == tcu::CUBEFACE_NEGATIVE_X || face == tcu::CUBEFACE_POSITIVE_X ? 2 : 0;
536 int texCoordTRow = face == tcu::CUBEFACE_NEGATIVE_Y || face == tcu::CUBEFACE_POSITIVE_Y ? 2 : 1;
537 texCoord[6 + texCoordSRow] *= texCoordTopRightFactor.x();
538 texCoord[9 + texCoordSRow] *= texCoordTopRightFactor.x();
539 texCoord[3 + texCoordTRow] *= texCoordTopRightFactor.y();
540 texCoord[9 + texCoordTRow] *= texCoordTopRightFactor.y();
541 }
542
543 gl.viewport(x + curX, y + curY, curW, curH);
544
545 renderer.renderQuad(0, &texCoord[0], params);
546
547 sampleTexture(tcu::SurfaceAccess(dstRef, curX, curY, curW, curH), refTexture, &texCoord[0], params);
548 }
549
550 GLU_EXPECT_NO_ERROR(gl.getError(), "Post render");
551 }
552
iterate(void)553 TextureCubeFilteringCase::IterateResult TextureCubeFilteringCase::iterate(void)
554 {
555 const glw::Functions &gl = m_renderCtx.getFunctions();
556 TestLog &log = m_testCtx.getLog();
557 const int cellSize = 28;
558 const int defViewportWidth = cellSize * 6;
559 const int defViewportHeight = cellSize * 4;
560 RandomViewport viewport(m_renderCtx.getRenderTarget(), cellSize * 6, cellSize * 4, deStringHash(getName()));
561 tcu::Surface renderedFrame(viewport.width, viewport.height);
562 tcu::Surface referenceFrame(viewport.width, viewport.height);
563 ReferenceParams sampleParams(TEXTURETYPE_CUBE);
564 const tcu::TextureFormat &texFmt = m_textures[0]->getRefTexture().getFormat();
565 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
566
567 // Accuracy measurements are off unless viewport size is exactly as expected.
568 if (getNodeType() == tcu::NODETYPE_ACCURACY &&
569 (viewport.width < defViewportWidth || viewport.height < defViewportHeight))
570 throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
571
572 // Viewport is divided into 4 sections.
573 int leftWidth = viewport.width / 2;
574 int rightWidth = viewport.width - leftWidth;
575 int bottomHeight = viewport.height / 2;
576 int topHeight = viewport.height - bottomHeight;
577
578 int curTexNdx = 0;
579
580 // Sampling parameters.
581 sampleParams.sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
582 sampleParams.sampler.seamlessCubeMap = true;
583 sampleParams.samplerType = getSamplerType(texFmt);
584 sampleParams.colorBias = fmtInfo.lookupBias;
585 sampleParams.colorScale = fmtInfo.lookupScale;
586 sampleParams.lodMode = LODMODE_EXACT;
587
588 // Use unit 0.
589 gl.activeTexture(GL_TEXTURE0);
590
591 // Setup gradient texture.
592 gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textures[curTexNdx]->getGLTexture());
593 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS);
594 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT);
595 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter);
596 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter);
597
598 // Bottom left: Minification
599 renderFaces(gl,
600 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, leftWidth,
601 bottomHeight),
602 m_textures[curTexNdx]->getRefTexture(), sampleParams, m_renderer, viewport.x, viewport.y, leftWidth,
603 bottomHeight, m_onlySampleFaceInterior ? tcu::Vec2(-0.81f, -0.81f) : tcu::Vec2(-0.975f, -0.975f),
604 m_onlySampleFaceInterior ? tcu::Vec2(0.8f, 0.8f) : tcu::Vec2(0.975f, 0.975f),
605 !m_onlySampleFaceInterior ? tcu::Vec2(1.3f, 1.25f) : tcu::Vec2(1.0f, 1.0f));
606
607 // Bottom right: Magnification
608 renderFaces(gl,
609 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, 0,
610 rightWidth, bottomHeight),
611 m_textures[curTexNdx]->getRefTexture(), sampleParams, m_renderer, viewport.x + leftWidth, viewport.y,
612 rightWidth, bottomHeight, tcu::Vec2(0.5f, 0.65f),
613 m_onlySampleFaceInterior ? tcu::Vec2(0.8f, 0.8f) : tcu::Vec2(0.975f, 0.975f),
614 !m_onlySampleFaceInterior ? tcu::Vec2(1.1f, 1.06f) : tcu::Vec2(1.0f, 1.0f));
615
616 if (m_textures.size() >= 2)
617 {
618 curTexNdx += 1;
619
620 // Setup second texture.
621 gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textures[curTexNdx]->getGLTexture());
622 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS);
623 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT);
624 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter);
625 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter);
626 }
627
628 // Top left: Minification
629 renderFaces(gl,
630 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, bottomHeight,
631 leftWidth, topHeight),
632 m_textures[curTexNdx]->getRefTexture(), sampleParams, m_renderer, viewport.x, viewport.y + bottomHeight,
633 leftWidth, topHeight,
634 m_onlySampleFaceInterior ? tcu::Vec2(-0.81f, -0.81f) : tcu::Vec2(-0.975f, -0.975f),
635 m_onlySampleFaceInterior ? tcu::Vec2(0.8f, 0.8f) : tcu::Vec2(0.975f, 0.975f),
636 !m_onlySampleFaceInterior ? tcu::Vec2(1.3f, 1.25f) : tcu::Vec2(1.0f, 1.0f));
637
638 // Top right: Magnification
639 renderFaces(gl,
640 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth,
641 bottomHeight, rightWidth, topHeight),
642 m_textures[curTexNdx]->getRefTexture(), sampleParams, m_renderer, viewport.x + leftWidth,
643 viewport.y + bottomHeight, rightWidth, topHeight, tcu::Vec2(0.5f, -0.65f),
644 m_onlySampleFaceInterior ? tcu::Vec2(0.8f, -0.8f) : tcu::Vec2(0.975f, -0.975f),
645 !m_onlySampleFaceInterior ? tcu::Vec2(1.1f, 1.06f) : tcu::Vec2(1.0f, 1.0f));
646
647 // Read result.
648 glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
649
650 // Compare and log.
651 {
652 const int bestScoreDiff = 16;
653 const int worstScoreDiff = 10000;
654
655 int score = measureAccuracy(log, referenceFrame, renderedFrame, bestScoreDiff, worstScoreDiff);
656 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str());
657 }
658
659 return STOP;
660 }
661
TextureFilteringTests(Context & context)662 TextureFilteringTests::TextureFilteringTests(Context &context)
663 : TestCaseGroup(context, "filter", "Texture Filtering Accuracy Tests")
664 {
665 }
666
~TextureFilteringTests(void)667 TextureFilteringTests::~TextureFilteringTests(void)
668 {
669 }
670
init(void)671 void TextureFilteringTests::init(void)
672 {
673 tcu::TestCaseGroup *group2D = new tcu::TestCaseGroup(m_testCtx, "2d", "2D Texture Filtering");
674 tcu::TestCaseGroup *groupCube = new tcu::TestCaseGroup(m_testCtx, "cube", "Cube Map Filtering");
675 addChild(group2D);
676 addChild(groupCube);
677
678 static const struct
679 {
680 const char *name;
681 uint32_t mode;
682 } wrapModes[] = {{"clamp", GL_CLAMP_TO_EDGE}, {"repeat", GL_REPEAT}, {"mirror", GL_MIRRORED_REPEAT}};
683
684 static const struct
685 {
686 const char *name;
687 uint32_t mode;
688 } minFilterModes[] = {{"nearest", GL_NEAREST},
689 {"linear", GL_LINEAR},
690 {"nearest_mipmap_nearest", GL_NEAREST_MIPMAP_NEAREST},
691 {"linear_mipmap_nearest", GL_LINEAR_MIPMAP_NEAREST},
692 {"nearest_mipmap_linear", GL_NEAREST_MIPMAP_LINEAR},
693 {"linear_mipmap_linear", GL_LINEAR_MIPMAP_LINEAR}};
694
695 static const struct
696 {
697 const char *name;
698 uint32_t mode;
699 } magFilterModes[] = {{"nearest", GL_NEAREST}, {"linear", GL_LINEAR}};
700
701 static const struct
702 {
703 const char *name;
704 int width;
705 int height;
706 } sizes2D[] = {{"pot", 32, 64}, {"npot", 31, 55}};
707
708 static const struct
709 {
710 const char *name;
711 int width;
712 int height;
713 } sizesCube[] = {{"pot", 64, 64}, {"npot", 63, 63}};
714
715 static const struct
716 {
717 const char *name;
718 uint32_t format;
719 } formats[] = {{"rgba8", GL_RGBA8}};
720
721 #define FOR_EACH(ITERATOR, ARRAY, BODY) \
722 for (int ITERATOR = 0; ITERATOR < DE_LENGTH_OF_ARRAY(ARRAY); ITERATOR++) \
723 BODY
724
725 // 2D cases.
726 FOR_EACH(minFilter, minFilterModes,
727 FOR_EACH(magFilter, magFilterModes,
728 FOR_EACH(wrapMode, wrapModes,
729 FOR_EACH(format, formats, FOR_EACH(size, sizes2D, {
730 string name = string("") + minFilterModes[minFilter].name + "_" +
731 magFilterModes[magFilter].name + "_" +
732 wrapModes[wrapMode].name + "_" + formats[format].name +
733 string("_") + sizes2D[size].name;
734
735 group2D->addChild(new Texture2DFilteringCase(
736 m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
737 name.c_str(), "", minFilterModes[minFilter].mode,
738 magFilterModes[magFilter].mode, wrapModes[wrapMode].mode,
739 wrapModes[wrapMode].mode, formats[format].format, sizes2D[size].width,
740 sizes2D[size].height));
741 })))))
742
743 // Cubemap cases.
744 FOR_EACH(minFilter, minFilterModes,
745 FOR_EACH(magFilter, magFilterModes,
746 FOR_EACH(wrapMode, wrapModes,
747 FOR_EACH(format, formats, FOR_EACH(size, sizesCube, {
748 string name = string("") + minFilterModes[minFilter].name + "_" +
749 magFilterModes[magFilter].name + "_" +
750 wrapModes[wrapMode].name + "_" + formats[format].name +
751 string("_") + sizesCube[size].name;
752
753 groupCube->addChild(new TextureCubeFilteringCase(
754 m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
755 name.c_str(), "", minFilterModes[minFilter].mode,
756 magFilterModes[magFilter].mode, wrapModes[wrapMode].mode,
757 wrapModes[wrapMode].mode, false, formats[format].format,
758 sizesCube[size].width, sizesCube[size].height));
759 })))))
760 }
761
762 } // namespace Accuracy
763 } // namespace gles3
764 } // namespace deqp
765