1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 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 FBO colorbuffer tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fFboColorbufferTests.hpp"
25#include "es31fFboTestCase.hpp"
26#include "es31fFboTestUtil.hpp"
27
28#include "gluTextureUtil.hpp"
29#include "gluContextInfo.hpp"
30
31#include "tcuCommandLine.hpp"
32#include "tcuImageCompare.hpp"
33#include "tcuRGBA.hpp"
34#include "tcuTestLog.hpp"
35#include "tcuTextureUtil.hpp"
36
37#include "sglrContextUtil.hpp"
38
39#include "deRandom.hpp"
40#include "deString.h"
41
42#include "glwEnums.hpp"
43
44namespace deqp
45{
46namespace gles31
47{
48namespace Functional
49{
50
51using std::string;
52using tcu::Vec2;
53using tcu::Vec3;
54using tcu::Vec4;
55using tcu::IVec2;
56using tcu::IVec3;
57using tcu::IVec4;
58using tcu::UVec4;
59using tcu::TestLog;
60using namespace FboTestUtil;
61
62const tcu::RGBA MIN_THRESHOLD(12, 12, 12, 12);
63
64static tcu::Vec4 generateRandomColor (de::Random& random)
65{
66	tcu::Vec4 retVal;
67
68	retVal[0] = random.getFloat();
69	retVal[1] = random.getFloat();
70	retVal[2] = random.getFloat();
71	retVal[3] = 1.0f;
72
73	return retVal;
74}
75
76static tcu::CubeFace getCubeFaceFromNdx (int ndx)
77{
78	switch (ndx)
79	{
80		case 0:	return tcu::CUBEFACE_POSITIVE_X;
81		case 1:	return tcu::CUBEFACE_NEGATIVE_X;
82		case 2:	return tcu::CUBEFACE_POSITIVE_Y;
83		case 3:	return tcu::CUBEFACE_NEGATIVE_Y;
84		case 4:	return tcu::CUBEFACE_POSITIVE_Z;
85		case 5:	return tcu::CUBEFACE_NEGATIVE_Z;
86		default:
87			DE_ASSERT(false);
88			return tcu::CUBEFACE_LAST;
89	}
90}
91
92class FboColorbufferCase : public FboTestCase
93{
94public:
95	FboColorbufferCase (Context& context, const char* name, const char* desc, const deUint32 format)
96		: FboTestCase	(context, name, desc)
97		, m_format		(format)
98	{
99	}
100
101	bool compare (const tcu::Surface& reference, const tcu::Surface& result)
102	{
103		const tcu::RGBA threshold (tcu::max(getFormatThreshold(m_format), MIN_THRESHOLD));
104
105		m_testCtx.getLog() << TestLog::Message << "Comparing images, threshold: " << threshold << TestLog::EndMessage;
106
107		return tcu::bilinearCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference.getAccess(), result.getAccess(), threshold, tcu::COMPARE_LOG_RESULT);
108	}
109
110protected:
111	const deUint32	m_format;
112};
113
114class FboColorTexCubeArrayCase : public FboColorbufferCase
115{
116public:
117	FboColorTexCubeArrayCase (Context& context, const char* name, const char* description, deUint32 texFmt, const IVec3& texSize)
118		: FboColorbufferCase	(context, name, description, texFmt)
119		, m_texSize				(texSize)
120	{
121		DE_ASSERT(texSize.z() % 6 == 0);
122	}
123
124protected:
125	void preCheck (void)
126	{
127		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_cube_map_array"))
128			throw tcu::NotSupportedError("GL_EXT_texture_cube_map_array not supported");
129
130		checkFormatSupport(m_format);
131	}
132
133	void render (tcu::Surface& dst)
134	{
135		TestLog&				log					= m_testCtx.getLog();
136		de::Random				rnd					(deStringHash(getName()) ^ 0xed607a89 ^ m_testCtx.getCommandLine().getBaseSeed());
137		tcu::TextureFormat		texFmt				= glu::mapGLInternalFormat(m_format);
138		tcu::TextureFormatInfo	fmtInfo				= tcu::getTextureFormatInfo(texFmt);
139
140		Texture2DShader			texToFboShader		(DataTypes() << glu::TYPE_SAMPLER_2D, getFragmentOutputType(texFmt), fmtInfo.valueMax-fmtInfo.valueMin, fmtInfo.valueMin);
141		TextureCubeArrayShader	arrayTexShader		(glu::getSamplerCubeArrayType(texFmt), glu::TYPE_FLOAT_VEC4);
142
143		deUint32				texToFboShaderID	= getCurrentContext()->createProgram(&texToFboShader);
144		deUint32				arrayTexShaderID	= getCurrentContext()->createProgram(&arrayTexShader);
145
146		// Setup textures
147		texToFboShader.setUniforms(*getCurrentContext(), texToFboShaderID);
148		arrayTexShader.setTexScaleBias(fmtInfo.lookupScale, fmtInfo.lookupBias);
149
150		// Framebuffers.
151		std::vector<deUint32>	fbos;
152		deUint32				tex;
153
154		{
155			glu::TransferFormat	transferFmt		= glu::getTransferFormat(texFmt);
156			bool				isFilterable	= glu::isGLInternalColorFormatFilterable(m_format);
157			const IVec3&		size			= m_texSize;
158
159			log << TestLog::Message
160				<< "Creating a cube map array texture ("
161				<< size.x() << "x" << size.y()
162				<< ", depth: "
163				<< size.z() << ")"
164				<< TestLog::EndMessage;
165
166			glGenTextures(1, &tex);
167
168			glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, tex);
169			glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
170			glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
171			glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY,	GL_TEXTURE_WRAP_R,		GL_CLAMP_TO_EDGE);
172			glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY,	GL_TEXTURE_MIN_FILTER,	isFilterable ? GL_LINEAR : GL_NEAREST);
173			glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY,	GL_TEXTURE_MAG_FILTER,	isFilterable ? GL_LINEAR : GL_NEAREST);
174			glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, m_format, size.x(), size.y(), size.z(), 0, transferFmt.format, transferFmt.dataType, DE_NULL);
175
176			log << TestLog::Message << "Creating a framebuffer object for each layer-face" << TestLog::EndMessage;
177
178			// Generate an FBO for each layer-face
179			for (int ndx = 0; ndx < m_texSize.z(); ndx++)
180			{
181				deUint32 layerFbo;
182
183				glGenFramebuffers(1, &layerFbo);
184				glBindFramebuffer(GL_FRAMEBUFFER, layerFbo);
185				glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, ndx);
186				checkError();
187				checkFramebufferStatus(GL_FRAMEBUFFER);
188
189				fbos.push_back(layerFbo);
190			}
191		}
192
193		log << TestLog::Message << "Rendering test images to layer-faces in randomized order" << TestLog::EndMessage;
194
195		{
196			std::vector<int> order(fbos.size());
197
198			for (size_t n = 0; n < order.size(); n++)
199				order[n] = (int)n;
200			rnd.shuffle(order.begin(), order.end());
201
202			for (size_t ndx = 0; ndx < order.size(); ndx++)
203			{
204				const int			layerFace	= order[ndx];
205				const deUint32		format		= GL_RGBA;
206				const deUint32		dataType	= GL_UNSIGNED_BYTE;
207				const int			texW		= 128;
208				const int			texH		= 128;
209				deUint32			tmpTex		= 0;
210				const deUint32		fbo			= fbos[layerFace];
211				const IVec3&		viewport	= m_texSize;
212				tcu::TextureLevel	data		(glu::mapGLTransferFormat(format, dataType), texW, texH, 1);
213
214				tcu::fillWithGrid(data.getAccess(), 8, generateRandomColor(rnd), Vec4(0.0f));
215
216				glGenTextures(1, &tmpTex);
217				glBindTexture(GL_TEXTURE_2D, tmpTex);
218				glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
219				glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
220				glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	GL_LINEAR);
221				glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	GL_LINEAR);
222				glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr());
223
224				glBindFramebuffer(GL_FRAMEBUFFER, fbo);
225				glViewport(0, 0, viewport.x(), viewport.y());
226				sglr::drawQuad(*getCurrentContext(), texToFboShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
227				checkError();
228
229				// Render to framebuffer
230				{
231					const Vec3			p0		= Vec3(float(ndx % 2) - 1.0f, float(ndx / 2) - 1.0f, 0.0f);
232					const Vec3			p1		= p0 + Vec3(1.0f, 1.0f, 0.0f);
233					const int			layer	= layerFace / 6;
234					const tcu::CubeFace	face	= getCubeFaceFromNdx(layerFace % 6);
235
236					glBindFramebuffer(GL_FRAMEBUFFER, 0);
237					glViewport(0, 0, getWidth(), getHeight());
238
239					glActiveTexture(GL_TEXTURE0);
240					glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, tex);
241
242					arrayTexShader.setLayer(layer);
243					arrayTexShader.setFace(face);
244					arrayTexShader.setUniforms(*getCurrentContext(), arrayTexShaderID);
245
246					sglr::drawQuad(*getCurrentContext(), arrayTexShaderID, p0, p1);
247					checkError();
248				}
249			}
250		}
251
252		readPixels(dst, 0, 0, getWidth(), getHeight());
253	}
254
255private:
256	IVec3 m_texSize;
257};
258
259FboColorTests::FboColorTests (Context& context)
260	: TestCaseGroup(context, "color", "Colorbuffer tests")
261{
262}
263
264FboColorTests::~FboColorTests (void)
265{
266}
267
268void FboColorTests::init (void)
269{
270	static const deUint32 colorFormats[] =
271	{
272		// RGBA formats
273		GL_RGBA32I,
274		GL_RGBA32UI,
275		GL_RGBA16I,
276		GL_RGBA16UI,
277		GL_RGBA8,
278		GL_RGBA8I,
279		GL_RGBA8UI,
280		GL_SRGB8_ALPHA8,
281		GL_RGB10_A2,
282		GL_RGB10_A2UI,
283		GL_RGBA4,
284		GL_RGB5_A1,
285
286		// RGB formats
287		GL_RGB8,
288		GL_RGB565,
289
290		// RG formats
291		GL_RG32I,
292		GL_RG32UI,
293		GL_RG16I,
294		GL_RG16UI,
295		GL_RG8,
296		GL_RG8I,
297		GL_RG8UI,
298
299		// R formats
300		GL_R32I,
301		GL_R32UI,
302		GL_R16I,
303		GL_R16UI,
304		GL_R8,
305		GL_R8I,
306		GL_R8UI,
307
308		// GL_EXT_color_buffer_float
309		GL_RGBA32F,
310		GL_RGBA16F,
311		GL_R11F_G11F_B10F,
312		GL_RG32F,
313		GL_RG16F,
314		GL_R32F,
315		GL_R16F,
316
317		// GL_EXT_color_buffer_half_float
318		GL_RGB16F
319	};
320
321	// .texcubearray
322	{
323		tcu::TestCaseGroup* texCubeArrayGroup = new tcu::TestCaseGroup(m_testCtx, "texcubearray", "Cube map array texture tests");
324		addChild(texCubeArrayGroup);
325
326		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
327			texCubeArrayGroup->addChild(new FboColorTexCubeArrayCase(m_context, getFormatName(colorFormats[fmtNdx]), "",
328																	 colorFormats[fmtNdx], IVec3(128, 128, 12)));
329	}
330}
331
332} // Functional
333} // gles31
334} // deqp
335