1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 2.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 wrap mode tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es2fTextureWrapTests.hpp"
25 #include "glsTextureTestUtil.hpp"
26 #include "gluTexture.hpp"
27 #include "gluStrUtil.hpp"
28 #include "gluTextureUtil.hpp"
29 #include "gluPixelTransfer.hpp"
30 #include "tcuTestLog.hpp"
31 #include "tcuTextureUtil.hpp"
32
33 #include "glwEnums.hpp"
34 #include "glwFunctions.hpp"
35
36 namespace deqp
37 {
38 namespace gles2
39 {
40 namespace Functional
41 {
42
43 using std::string;
44 using std::vector;
45 using tcu::Sampler;
46 using tcu::TestLog;
47 using namespace glu;
48 using namespace gls::TextureTestUtil;
49 using namespace glu::TextureTestUtil;
50
51 enum
52 {
53 VIEWPORT_WIDTH = 256,
54 VIEWPORT_HEIGHT = 256
55 };
56
57 class TextureWrapCase : public tcu::TestCase
58 {
59 public:
60 TextureWrapCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const glu::ContextInfo &ctxInfo,
61 const char *name, const char *description, uint32_t format, uint32_t dataType, uint32_t wrapS,
62 uint32_t wrapT, uint32_t minFilter, uint32_t magFilter, int width, int height,
63 bool enableRelaxedRef = false);
64 TextureWrapCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const glu::ContextInfo &ctxInfo,
65 const char *name, const char *description, uint32_t wrapS, uint32_t wrapT, uint32_t minFilter,
66 uint32_t magFilter, const std::vector<std::string> &filenames, bool enableRelaxedRef = false);
67 ~TextureWrapCase(void);
68
69 void init(void);
70 void deinit(void);
71 IterateResult iterate(void);
72
73 private:
74 TextureWrapCase(const TextureWrapCase &other);
75 TextureWrapCase &operator=(const TextureWrapCase &other);
76
77 glu::RenderContext &m_renderCtx;
78 const glu::ContextInfo &m_renderCtxInfo;
79
80 uint32_t m_format;
81 uint32_t m_dataType;
82 uint32_t m_wrapS;
83 uint32_t m_wrapT;
84 uint32_t m_minFilter;
85 uint32_t m_magFilter;
86
87 int m_width;
88 int m_height;
89 std::vector<std::string> m_filenames;
90
91 glu::Texture2D *m_texture;
92 TextureRenderer m_renderer;
93
94 bool m_enableRelaxedRef;
95 };
96
TextureWrapCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const glu::ContextInfo & ctxInfo,const char * name,const char * description,uint32_t format,uint32_t dataType,uint32_t wrapS,uint32_t wrapT,uint32_t minFilter,uint32_t magFilter,int width,int height,bool enableRelaxedRef)97 TextureWrapCase::TextureWrapCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
98 const glu::ContextInfo &ctxInfo, const char *name, const char *description,
99 uint32_t format, uint32_t dataType, uint32_t wrapS, uint32_t wrapT, uint32_t minFilter,
100 uint32_t magFilter, int width, int height, bool enableRelaxedRef)
101 : TestCase(testCtx, name, description)
102 , m_renderCtx(renderCtx)
103 , m_renderCtxInfo(ctxInfo)
104 , m_format(format)
105 , m_dataType(dataType)
106 , m_wrapS(wrapS)
107 , m_wrapT(wrapT)
108 , m_minFilter(minFilter)
109 , m_magFilter(magFilter)
110 , m_width(width)
111 , m_height(height)
112 , m_texture(DE_NULL)
113 , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
114 , m_enableRelaxedRef(enableRelaxedRef)
115 {
116 }
117
TextureWrapCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const glu::ContextInfo & ctxInfo,const char * name,const char * description,uint32_t wrapS,uint32_t wrapT,uint32_t minFilter,uint32_t magFilter,const std::vector<std::string> & filenames,bool enableRelaxedRef)118 TextureWrapCase::TextureWrapCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
119 const glu::ContextInfo &ctxInfo, const char *name, const char *description,
120 uint32_t wrapS, uint32_t wrapT, uint32_t minFilter, uint32_t magFilter,
121 const std::vector<std::string> &filenames, bool enableRelaxedRef)
122 : TestCase(testCtx, name, description)
123 , m_renderCtx(renderCtx)
124 , m_renderCtxInfo(ctxInfo)
125 , m_format(GL_NONE)
126 , m_dataType(GL_NONE)
127 , m_wrapS(wrapS)
128 , m_wrapT(wrapT)
129 , m_minFilter(minFilter)
130 , m_magFilter(magFilter)
131 , m_width(0)
132 , m_height(0)
133 , m_filenames(filenames)
134 , m_texture(DE_NULL)
135 , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
136 , m_enableRelaxedRef(enableRelaxedRef)
137 {
138 }
139
~TextureWrapCase(void)140 TextureWrapCase::~TextureWrapCase(void)
141 {
142 deinit();
143 }
144
init(void)145 void TextureWrapCase::init(void)
146 {
147 if (!m_filenames.empty())
148 {
149 DE_ASSERT(m_width == 0 && m_height == 0 && m_format == GL_NONE && m_dataType == GL_NONE);
150
151 m_texture = glu::Texture2D::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(),
152 (int)m_filenames.size(), m_filenames);
153 m_width = m_texture->getRefTexture().getWidth();
154 m_height = m_texture->getRefTexture().getHeight();
155 }
156 else
157 {
158 m_texture = new Texture2D(m_renderCtx, m_format, m_dataType, m_width, m_height);
159
160 // Fill level 0.
161 m_texture->getRefTexture().allocLevel(0);
162 if (m_wrapS == GL_REPEAT || m_wrapT == GL_REPEAT)
163 {
164 // If run in repeat mode, use conical style texture to avoid edge sample result have a huge difference when coordinate offset in allow range.
165 tcu::fillWithComponentGradients3(m_texture->getRefTexture().getLevel(0),
166 tcu::Vec4(-0.5f, -0.5f, -0.5f, 1.5f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f));
167 }
168 else
169 {
170 tcu::fillWithComponentGradients(m_texture->getRefTexture().getLevel(0),
171 tcu::Vec4(-0.5f, -0.5f, -0.5f, 1.5f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f));
172 }
173
174 m_texture->upload();
175 }
176 }
177
deinit(void)178 void TextureWrapCase::deinit(void)
179 {
180 delete m_texture;
181 m_texture = DE_NULL;
182
183 m_renderer.clear();
184 }
185
iterate(void)186 TextureWrapCase::IterateResult TextureWrapCase::iterate(void)
187 {
188 const glw::Functions &gl = m_renderCtx.getFunctions();
189 TestLog &log = m_testCtx.getLog();
190 RandomViewport viewport(m_renderCtx.getRenderTarget(), VIEWPORT_WIDTH, VIEWPORT_HEIGHT, deStringHash(getName()));
191 tcu::Surface renderedFrame(viewport.width, viewport.height);
192 tcu::Surface referenceFrame(viewport.width, viewport.height);
193 bool isCompressedTex = !m_filenames.empty();
194 ReferenceParams refParams(TEXTURETYPE_2D);
195 int leftWidth = viewport.width / 2;
196 int rightWidth = viewport.width - leftWidth;
197 vector<float> texCoord;
198
199 tcu::RGBA threshold;
200 if (m_texture->getRefTexture().getFormat().type == tcu::TextureFormat::UNORM_SHORT_4444 ||
201 m_texture->getRefTexture().getFormat().type == tcu::TextureFormat::UNSIGNED_SHORT_4444)
202 {
203 threshold = tcu::PixelFormat(4, 4, 4, 4).getColorThreshold() + tcu::RGBA(1, 1, 1, 1);
204 }
205 else
206 {
207 threshold = m_renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() +
208 (isCompressedTex ? tcu::RGBA(7, 7, 7, 7) : tcu::RGBA(3, 3, 3, 3));
209 }
210
211 // Bind to unit 0.
212 gl.activeTexture(GL_TEXTURE0);
213 gl.bindTexture(GL_TEXTURE_2D, m_texture->getGLTexture());
214
215 // Setup filtering and wrap modes.
216 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS);
217 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT);
218 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter);
219 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter);
220
221 GLU_EXPECT_NO_ERROR(gl.getError(), "Set texturing state");
222
223 // Parameters for reference images.
224 refParams.sampler = mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
225 refParams.lodMode = LODMODE_EXACT;
226
227 // Left: minification
228 {
229 gl.viewport(viewport.x, viewport.y, leftWidth, viewport.height);
230
231 computeQuadTexCoord2D(texCoord, tcu::Vec2(-1.5f, -3.0f), tcu::Vec2(1.5f, 2.5f));
232
233 m_renderer.renderQuad(0, &texCoord[0], refParams);
234 glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
235
236 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0,
237 leftWidth, viewport.height),
238 m_texture->getRefTexture(), &texCoord[0], refParams);
239 }
240
241 // Right: magnification
242 {
243 gl.viewport(viewport.x + leftWidth, viewport.y, rightWidth, viewport.height);
244
245 computeQuadTexCoord2D(texCoord, tcu::Vec2(-0.5f, 0.75f), tcu::Vec2(0.25f, 1.25f));
246
247 m_renderer.renderQuad(0, &texCoord[0], refParams);
248 glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
249
250 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, 0,
251 rightWidth, viewport.height),
252 m_texture->getRefTexture(), &texCoord[0], refParams);
253 }
254
255 // Compare and log.
256 bool isOk = compareImages(log, referenceFrame, renderedFrame, threshold);
257
258 if ((isOk == false) && m_enableRelaxedRef && m_renderer.getTexCoordPrecision() != PRECISION_HIGHP)
259 {
260 refParams.float16TexCoord = true;
261 // Left: minification
262 {
263 computeQuadTexCoord2D(texCoord, tcu::Vec2(-1.5f, -3.0f), tcu::Vec2(1.5f, 2.5f));
264 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0,
265 leftWidth, viewport.height),
266 m_texture->getRefTexture(), &texCoord[0], refParams);
267 }
268
269 // Right: magnification
270 {
271 computeQuadTexCoord2D(texCoord, tcu::Vec2(-0.5f, 0.75f), tcu::Vec2(0.25f, 1.25f));
272 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth,
273 0, rightWidth, viewport.height),
274 m_texture->getRefTexture(), &texCoord[0], refParams);
275 }
276
277 isOk |= compareImages(log, referenceFrame, renderedFrame, threshold);
278 }
279
280 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
281 isOk ? "Pass" : "Image comparison failed");
282
283 return STOP;
284 }
285
TextureWrapTests(Context & context)286 TextureWrapTests::TextureWrapTests(Context &context) : TestCaseGroup(context, "wrap", "Wrap Mode Tests")
287 {
288 }
289
~TextureWrapTests(void)290 TextureWrapTests::~TextureWrapTests(void)
291 {
292 }
293
init(void)294 void TextureWrapTests::init(void)
295 {
296 static const struct
297 {
298 const char *name;
299 uint32_t mode;
300 } wrapModes[] = {{"clamp", GL_CLAMP_TO_EDGE}, {"repeat", GL_REPEAT}, {"mirror", GL_MIRRORED_REPEAT}};
301
302 static const struct
303 {
304 const char *name;
305 uint32_t mode;
306 } filteringModes[] = {{"nearest", GL_NEAREST}, {"linear", GL_LINEAR}};
307
308 static const struct
309 {
310 const char *name;
311 int width;
312 int height;
313 } sizes[] = {{"pot", 64, 128}, {"npot", 63, 112}};
314
315 static const struct
316 {
317 const char *name;
318 uint32_t format;
319 uint32_t dataType;
320 } formats[] = {
321 {"rgba8888", GL_RGBA, GL_UNSIGNED_BYTE},
322 {"rgb888", GL_RGB, GL_UNSIGNED_BYTE},
323 {"rgba4444", GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4},
324 {"l8", GL_LUMINANCE, GL_UNSIGNED_BYTE},
325 };
326
327 #define FOR_EACH(ITERATOR, ARRAY, BODY) \
328 for (int ITERATOR = 0; ITERATOR < DE_LENGTH_OF_ARRAY(ARRAY); ITERATOR++) \
329 BODY
330
331 FOR_EACH(
332 wrapS, wrapModes,
333 FOR_EACH(
334 wrapT, wrapModes,
335 FOR_EACH(filter, filteringModes,
336 FOR_EACH(size, sizes, FOR_EACH(format, formats, {
337 bool is_clamp_clamp = (wrapModes[wrapS].mode == GL_CLAMP_TO_EDGE &&
338 wrapModes[wrapT].mode == GL_CLAMP_TO_EDGE);
339 bool is_repeat_mirror = (wrapModes[wrapS].mode == GL_REPEAT &&
340 wrapModes[wrapT].mode == GL_MIRRORED_REPEAT);
341 bool enableRelaxedPrecisionRef = wrapModes[wrapS].mode == GL_REPEAT ||
342 wrapModes[wrapT].mode == GL_REPEAT ||
343 wrapModes[wrapS].mode == GL_MIRRORED_REPEAT ||
344 wrapModes[wrapT].mode == GL_MIRRORED_REPEAT;
345
346 if (!is_clamp_clamp && !is_repeat_mirror && format != 0)
347 continue; // Use other format varants with clamp_clamp & repeat_mirror pair only.
348
349 if (!is_clamp_clamp &&
350 (!deIsPowerOfTwo32(sizes[size].width) || !deIsPowerOfTwo32(sizes[size].height)))
351 continue; // Not supported as described in Spec section 3.8.2.
352
353 string name = string("") + wrapModes[wrapS].name + "_" + wrapModes[wrapT].name + "_" +
354 filteringModes[filter].name + "_" + sizes[size].name + "_" +
355 formats[format].name;
356 addChild(new TextureWrapCase(
357 m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), name.c_str(),
358 "", formats[format].format, formats[format].dataType, wrapModes[wrapS].mode,
359 wrapModes[wrapT].mode, filteringModes[filter].mode, filteringModes[filter].mode,
360 sizes[size].width, sizes[size].height, enableRelaxedPrecisionRef));
361 })))))
362
363 // Power-of-two ETC1 texture
364 std::vector<std::string> potFilenames;
365 potFilenames.push_back("data/etc1/photo_helsinki_mip_0.pkm");
366
367 FOR_EACH(wrapS, wrapModes,
368 FOR_EACH(wrapT, wrapModes, FOR_EACH(filter, filteringModes, {
369 bool enableRelaxedPrecisionRef = wrapModes[wrapS].mode == GL_REPEAT ||
370 wrapModes[wrapT].mode == GL_REPEAT ||
371 wrapModes[wrapS].mode == GL_MIRRORED_REPEAT ||
372 wrapModes[wrapT].mode == GL_MIRRORED_REPEAT;
373
374 string name = string("") + wrapModes[wrapS].name + "_" + wrapModes[wrapT].name + "_" +
375 filteringModes[filter].name + "_pot_etc1";
376 addChild(new TextureWrapCase(
377 m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), name.c_str(), "",
378 wrapModes[wrapS].mode, wrapModes[wrapT].mode, filteringModes[filter].mode,
379 filteringModes[filter].mode, potFilenames, enableRelaxedPrecisionRef));
380 })))
381
382 std::vector<std::string> npotFilenames;
383 npotFilenames.push_back("data/etc1/photo_helsinki_113x89.pkm");
384
385 // NPOT ETC1 texture
386 for (int filter = 0; filter < DE_LENGTH_OF_ARRAY(filteringModes); filter++)
387 {
388 string name = string("clamp_clamp_") + filteringModes[filter].name + "_npot_etc1";
389 addChild(new TextureWrapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), name.c_str(),
390 "", GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, filteringModes[filter].mode,
391 filteringModes[filter].mode, npotFilenames));
392 }
393 }
394
395 } // namespace Functional
396 } // namespace gles2
397 } // namespace deqp
398