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 swizzle tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es3fTextureSwizzleTests.hpp"
25#include "glsTextureTestUtil.hpp"
26#include "gluPixelTransfer.hpp"
27#include "gluTexture.hpp"
28#include "gluRenderContext.hpp"
29#include "tcuTextureUtil.hpp"
30#include "tcuRenderTarget.hpp"
31#include "deString.h"
32#include "glwEnums.hpp"
33#include "glwFunctions.hpp"
34
35namespace deqp
36{
37namespace gles3
38{
39namespace Functional
40{
41
42using std::string;
43using std::vector;
44using tcu::TestLog;
45using namespace deqp::gls;
46using namespace deqp::gls::TextureTestUtil;
47using namespace glu::TextureTestUtil;
48
49static int swizzle (const tcu::RGBA& c, deUint32 swz)
50{
51	switch (swz)
52	{
53		case GL_RED:	return c.getRed();
54		case GL_GREEN:	return c.getGreen();
55		case GL_BLUE:	return c.getBlue();
56		case GL_ALPHA:	return c.getAlpha();
57		case GL_ZERO:	return 0;
58		case GL_ONE:	return (1<<8)-1;
59		default:
60			DE_ASSERT(false);
61			return 0;
62	}
63}
64
65static void swizzle (tcu::Surface& surface, deUint32 swzR, deUint32 swzG, deUint32 swzB, deUint32 swzA)
66{
67	for (int y = 0; y < surface.getHeight(); y++)
68	{
69		for (int x = 0; x < surface.getWidth(); x++)
70		{
71			tcu::RGBA p = surface.getPixel(x, y);
72			surface.setPixel(x, y, tcu::RGBA(swizzle(p, swzR), swizzle(p, swzG), swizzle(p, swzB), swizzle(p, swzA)));
73		}
74	}
75}
76
77class Texture2DSwizzleCase : public TestCase
78{
79public:
80							Texture2DSwizzleCase	(Context& context, const char* name, const char* description, deUint32 internalFormat, deUint32 format, deUint32 dataType, deUint32 swizzleR, deUint32 swizzleG, deUint32 swizzleB, deUint32 swizzleA);
81							~Texture2DSwizzleCase	(void);
82
83	void					init					(void);
84	void					deinit					(void);
85	IterateResult			iterate					(void);
86
87private:
88							Texture2DSwizzleCase	(const Texture2DSwizzleCase& other);
89	Texture2DSwizzleCase&	operator=				(const Texture2DSwizzleCase& other);
90
91	deUint32				m_internalFormat;
92	deUint32				m_format;
93	deUint32				m_dataType;
94	deUint32				m_swizzleR;
95	deUint32				m_swizzleG;
96	deUint32				m_swizzleB;
97	deUint32				m_swizzleA;
98
99	glu::Texture2D*			m_texture;
100	TextureRenderer			m_renderer;
101};
102
103Texture2DSwizzleCase::Texture2DSwizzleCase (Context& context, const char* name, const char* description, deUint32 internalFormat, deUint32 format, deUint32 dataType, deUint32 swizzleR, deUint32 swizzleG, deUint32 swizzleB, deUint32 swizzleA)
104	: TestCase			(context, name, description)
105	, m_internalFormat	(internalFormat)
106	, m_format			(format)
107	, m_dataType		(dataType)
108	, m_swizzleR		(swizzleR)
109	, m_swizzleG		(swizzleG)
110	, m_swizzleB		(swizzleB)
111	, m_swizzleA		(swizzleA)
112	, m_texture			(DE_NULL)
113	, m_renderer		(context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
114{
115}
116
117Texture2DSwizzleCase::~Texture2DSwizzleCase (void)
118{
119	deinit();
120}
121
122void Texture2DSwizzleCase::init (void)
123{
124	int	width	= de::min(128, m_context.getRenderContext().getRenderTarget().getWidth());
125	int	height	= de::min(128, m_context.getRenderContext().getRenderTarget().getHeight());
126
127	m_texture = (m_internalFormat == m_format) ? new glu::Texture2D(m_context.getRenderContext(), m_format, m_dataType, width, height)
128											   : new glu::Texture2D(m_context.getRenderContext(), m_internalFormat, width, height);
129
130	tcu::TextureFormatInfo spec = tcu::getTextureFormatInfo(m_texture->getRefTexture().getFormat());
131
132	// Fill level 0.
133	m_texture->getRefTexture().allocLevel(0);
134	tcu::fillWithComponentGradients(m_texture->getRefTexture().getLevel(0), spec.valueMin, spec.valueMax);
135}
136
137void Texture2DSwizzleCase::deinit (void)
138{
139	delete m_texture;
140	m_texture = DE_NULL;
141
142	m_renderer.clear();
143}
144
145Texture2DSwizzleCase::IterateResult Texture2DSwizzleCase::iterate (void)
146{
147	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
148	TestLog&				log					= m_testCtx.getLog();
149	RandomViewport			viewport			(m_context.getRenderContext().getRenderTarget(), m_texture->getRefTexture().getWidth(), m_texture->getRefTexture().getHeight(), deStringHash(getName()));
150	tcu::Surface			renderedFrame		(viewport.width, viewport.height);
151	tcu::Surface			referenceFrame		(viewport.width, viewport.height);
152	tcu::RGBA				threshold			= m_context.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(1,1,1,1);
153	vector<float>			texCoord;
154	ReferenceParams			renderParams		(TEXTURETYPE_2D);
155	tcu::TextureFormatInfo	spec				= tcu::getTextureFormatInfo(m_texture->getRefTexture().getFormat());
156
157	renderParams.samplerType	= getSamplerType(m_texture->getRefTexture().getFormat());
158	renderParams.sampler		= tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST);
159	renderParams.colorScale		= spec.lookupScale;
160	renderParams.colorBias		= spec.lookupBias;
161
162	computeQuadTexCoord2D(texCoord, tcu::Vec2(0.0f, 0.0f), tcu::Vec2(1.0f, 1.0f));
163
164	// Setup base viewport.
165	gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
166
167	// Upload texture data to GL.
168	m_texture->upload();
169
170	// Bind to unit 0.
171	gl.activeTexture(GL_TEXTURE0);
172	gl.bindTexture(GL_TEXTURE_2D, m_texture->getGLTexture());
173
174	// Setup nearest neighbor filtering and clamp-to-edge.
175	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
176	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
177	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,	GL_NEAREST);
178	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,	GL_NEAREST);
179
180	// Setup texture swizzle.
181	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R,	m_swizzleR);
182	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G,	m_swizzleG);
183	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B,	m_swizzleB);
184	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A,	m_swizzleA);
185
186	GLU_EXPECT_NO_ERROR(gl.getError(), "Set texturing state");
187
188	// Draw.
189	m_renderer.renderQuad(0, &texCoord[0], renderParams);
190	glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, renderedFrame.getAccess());
191
192	// Compute reference
193	{
194		const tcu::PixelFormat pixelFormat = m_context.getRenderTarget().getPixelFormat();
195
196		// Do initial rendering to RGBA8 in order to keep alpha
197		sampleTexture(tcu::SurfaceAccess(referenceFrame, tcu::PixelFormat(8,8,8,8)), m_texture->getRefTexture(), &texCoord[0], renderParams);
198
199		// Swizzle channels
200		swizzle(referenceFrame, m_swizzleR, m_swizzleG, m_swizzleB, m_swizzleA);
201
202		// Convert to destination format
203		if (pixelFormat != tcu::PixelFormat(8,8,8,8))
204		{
205			for (int y = 0; y < referenceFrame.getHeight(); y++)
206			{
207				for (int x = 0; x < referenceFrame.getWidth(); x++)
208				{
209					tcu::RGBA p = referenceFrame.getPixel(x, y);
210					referenceFrame.setPixel(x, y, pixelFormat.convertColor(p));
211				}
212			}
213		}
214	}
215
216	// Compare and log.
217	bool isOk = compareImages(log, referenceFrame, renderedFrame, threshold);
218
219	m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
220							isOk ? "Pass"				: "Image comparison failed");
221
222	return STOP;
223}
224
225TextureSwizzleTests::TextureSwizzleTests (Context& context)
226	: TestCaseGroup(context, "swizzle", "Texture Swizzle Tests")
227{
228}
229
230TextureSwizzleTests::~TextureSwizzleTests (void)
231{
232}
233
234void TextureSwizzleTests::init (void)
235{
236	static const struct
237	{
238		const char*		name;
239		deUint32		internalFormat;
240		deUint32		format;
241		deUint32		dataType;
242	} formats[] =
243	{
244		{ "alpha",				GL_ALPHA,				GL_ALPHA,			GL_UNSIGNED_BYTE },
245		{ "luminance",			GL_LUMINANCE,			GL_LUMINANCE,		GL_UNSIGNED_BYTE },
246		{ "luminance_alpha",	GL_LUMINANCE_ALPHA,		GL_LUMINANCE_ALPHA,	GL_UNSIGNED_BYTE },
247		{ "red",				GL_R8,					GL_RED,				GL_UNSIGNED_BYTE },
248		{ "rg",					GL_RG8,					GL_RG,				GL_UNSIGNED_BYTE },
249		{ "rgb",				GL_RGB8,				GL_RGB,				GL_UNSIGNED_BYTE },
250		{ "rgba",				GL_RGBA8,				GL_RGBA,			GL_UNSIGNED_BYTE }
251	};
252
253	static const struct
254	{
255		const char*		name;
256		deUint32		channel;
257	} channels[] =
258	{
259		{ "r",	GL_TEXTURE_SWIZZLE_R },
260		{ "g",	GL_TEXTURE_SWIZZLE_G },
261		{ "b",	GL_TEXTURE_SWIZZLE_B },
262		{ "a",	GL_TEXTURE_SWIZZLE_A }
263	};
264
265	static const struct
266	{
267		const char*		name;
268		deUint32		swizzle;
269	} swizzles[] =
270	{
271		{ "red",		GL_RED		},
272		{ "green",		GL_GREEN	},
273		{ "blue",		GL_BLUE		},
274		{ "alpha",		GL_ALPHA	},
275		{ "zero",		GL_ZERO		},
276		{ "one",		GL_ONE		}
277	};
278
279	static const struct
280	{
281		const char*		name;
282		deUint32		swzR;
283		deUint32		swzG;
284		deUint32		swzB;
285		deUint32		swzA;
286	} swizzleCases[] =
287	{
288		{ "all_red",			GL_RED,		GL_RED,		GL_RED,		GL_RED		},
289		{ "all_green",			GL_GREEN,	GL_GREEN,	GL_GREEN,	GL_GREEN	},
290		{ "all_blue",			GL_BLUE,	GL_BLUE,	GL_BLUE,	GL_BLUE		},
291		{ "all_alpha",			GL_ALPHA,	GL_ALPHA,	GL_ALPHA,	GL_ALPHA	},
292		{ "all_zero",			GL_ZERO,	GL_ZERO,	GL_ZERO,	GL_ZERO		},
293		{ "all_one",			GL_ONE,		GL_ONE,		GL_ONE,		GL_ONE		},
294		{ "bgra",				GL_BLUE,	GL_GREEN,	GL_RED,		GL_ALPHA	},
295		{ "abgr",				GL_ALPHA,	GL_BLUE,	GL_GREEN,	GL_RED		},
296		{ "one_one_red_green",	GL_ONE,		GL_ONE,		GL_RED,		GL_GREEN	}
297	};
298
299	static const deUint32 defaultSwizzles[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA };
300
301	// All swizzles applied to each channel.
302	tcu::TestCaseGroup* singleChannelGroup = new tcu::TestCaseGroup(m_testCtx, "single_channel", "Single-channel swizzle");
303	addChild(singleChannelGroup);
304	for (int chanNdx = 0; chanNdx < DE_LENGTH_OF_ARRAY(channels); chanNdx++)
305	{
306		for (int swzNdx = 0; swzNdx < DE_LENGTH_OF_ARRAY(swizzles); swzNdx++)
307		{
308			if (swizzles[swzNdx].swizzle == defaultSwizzles[chanNdx])
309				continue; // No need to test default case.
310
311			string		name	= string(channels[chanNdx].name) + "_" + swizzles[swzNdx].name;
312			deUint32	swz		= swizzles[swzNdx].swizzle;
313			deUint32	swzR	= (chanNdx == 0) ? swz : defaultSwizzles[0];
314			deUint32	swzG	= (chanNdx == 1) ? swz : defaultSwizzles[1];
315			deUint32	swzB	= (chanNdx == 2) ? swz : defaultSwizzles[2];
316			deUint32	swzA	= (chanNdx == 3) ? swz : defaultSwizzles[3];
317
318			singleChannelGroup->addChild(new Texture2DSwizzleCase(m_context, name.c_str(), "Single-channel swizzle", GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, swzR, swzG, swzB, swzA));
319		}
320	}
321
322	// Swizzles for all formats.
323	tcu::TestCaseGroup* multiChannelGroup = new tcu::TestCaseGroup(m_testCtx, "multi_channel", "Multi-channel swizzle");
324	addChild(multiChannelGroup);
325	for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(formats); fmtNdx++)
326	{
327		for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(swizzleCases); caseNdx++)
328		{
329			string		name		= string(formats[fmtNdx].name) + "_" + swizzleCases[caseNdx].name;
330			deUint32	swzR		= swizzleCases[caseNdx].swzR;
331			deUint32	swzG		= swizzleCases[caseNdx].swzG;
332			deUint32	swzB		= swizzleCases[caseNdx].swzB;
333			deUint32	swzA		= swizzleCases[caseNdx].swzA;
334			deUint32	intFormat	= formats[fmtNdx].internalFormat;
335			deUint32	format		= formats[fmtNdx].format;
336			deUint32	dataType	= formats[fmtNdx].dataType;
337
338			multiChannelGroup->addChild(new Texture2DSwizzleCase(m_context, name.c_str(), "Multi-channel swizzle", intFormat, format, dataType, swzR, swzG, swzB, swzA));
339		}
340	}
341}
342
343} // Functional
344} // gles3
345} // deqp
346