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 FBO colorbuffer tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es3fFboColorbufferTests.hpp"
25#include "es3fFboTestCase.hpp"
26#include "es3fFboTestUtil.hpp"
27#include "gluTextureUtil.hpp"
28#include "gluContextInfo.hpp"
29#include "tcuImageCompare.hpp"
30#include "tcuRGBA.hpp"
31#include "tcuTestLog.hpp"
32#include "tcuTextureUtil.hpp"
33#include "sglrContextUtil.hpp"
34#include "deRandom.hpp"
35#include "deString.h"
36#include "glwEnums.hpp"
37
38namespace deqp
39{
40namespace gles3
41{
42namespace Functional
43{
44
45using std::string;
46using tcu::Vec2;
47using tcu::Vec3;
48using tcu::Vec4;
49using tcu::IVec2;
50using tcu::IVec3;
51using tcu::IVec4;
52using tcu::UVec4;
53using tcu::TestLog;
54using namespace FboTestUtil;
55
56const tcu::RGBA MIN_THRESHOLD(12, 12, 12, 12);
57
58template <int Size>
59static tcu::Vector<float, Size> randomVector (de::Random& rnd, const tcu::Vector<float, Size>& minVal = tcu::Vector<float, Size>(0.0f), const tcu::Vector<float, Size>& maxVal = tcu::Vector<float, Size>(1.0f))
60{
61	tcu::Vector<float, Size> res;
62	for (int ndx = 0; ndx < Size; ndx++)
63		res[ndx] = rnd.getFloat(minVal[ndx], maxVal[ndx]);
64	return res;
65}
66
67static tcu::Vec4 generateRandomColor (de::Random& random)
68{
69	tcu::Vec4 retVal;
70
71	for (int i = 0; i < 3; ++i)
72		retVal[i] = random.getFloat();
73	retVal[3] = 1.0f;
74
75	return retVal;
76}
77
78class FboColorbufferCase : public FboTestCase
79{
80public:
81	FboColorbufferCase (Context& context, const char* name, const char* desc, const deUint32 format)
82		: FboTestCase			(context, name, desc)
83		, m_format				(format)
84	{
85	}
86
87	bool compare (const tcu::Surface& reference, const tcu::Surface& result)
88	{
89		const tcu::RGBA threshold (tcu::max(getFormatThreshold(m_format), MIN_THRESHOLD));
90
91		m_testCtx.getLog() << TestLog::Message << "Comparing images, threshold: " << threshold << TestLog::EndMessage;
92
93		return tcu::bilinearCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference.getAccess(), result.getAccess(), threshold, tcu::COMPARE_LOG_RESULT);
94	}
95
96protected:
97	const deUint32	m_format;
98};
99
100class FboColorClearCase : public FboColorbufferCase
101{
102public:
103	FboColorClearCase (Context& context, const char* name, const char* desc, deUint32 format, int width, int height)
104		: FboColorbufferCase	(context, name, desc, format)
105		, m_width				(width)
106		, m_height				(height)
107	{
108	}
109
110protected:
111	void preCheck (void)
112	{
113		checkFormatSupport(m_format);
114	}
115
116	void render (tcu::Surface& dst)
117	{
118		tcu::TextureFormat			fboFormat	= glu::mapGLInternalFormat(m_format);
119		tcu::TextureChannelClass	fmtClass	= tcu::getTextureChannelClass(fboFormat.type);
120		tcu::TextureFormatInfo		fmtInfo		= tcu::getTextureFormatInfo(fboFormat);
121		de::Random					rnd			(17);
122		const int					numClears	= 16;
123		deUint32					fbo			= 0;
124		deUint32					rbo			= 0;
125
126		glGenFramebuffers(1, &fbo);
127		glGenRenderbuffers(1, &rbo);
128
129		glBindRenderbuffer(GL_RENDERBUFFER, rbo);
130		glRenderbufferStorage(GL_RENDERBUFFER, m_format, m_width, m_height);
131		checkError();
132
133		glBindFramebuffer(GL_FRAMEBUFFER, fbo);
134		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
135		checkError();
136		checkFramebufferStatus(GL_FRAMEBUFFER);
137
138		glViewport(0, 0, m_width, m_height);
139
140		// Initialize to transparent black.
141		switch (fmtClass)
142		{
143			case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
144			case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
145			case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
146				glClearBufferfv(GL_COLOR, 0, Vec4(0.0f).getPtr());
147				break;
148
149			case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
150				glClearBufferuiv(GL_COLOR, 0, UVec4(0).getPtr());
151				break;
152
153			case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
154				glClearBufferiv(GL_COLOR, 0, IVec4(0).getPtr());
155				break;
156
157			default:
158				DE_ASSERT(DE_FALSE);
159		}
160
161		// Do random scissored clears.
162		glEnable(GL_SCISSOR_TEST);
163		for (int ndx = 0; ndx < numClears; ndx++)
164		{
165			int		x		= rnd.getInt(0, m_width		- 1);
166			int		y		= rnd.getInt(0, m_height	- 1);
167			int		w		= rnd.getInt(1, m_width		- x);
168			int		h		= rnd.getInt(1, m_height	- y);
169			Vec4	color	= randomVector<4>(rnd, fmtInfo.valueMin, fmtInfo.valueMax);
170
171			glScissor(x, y, w, h);
172
173			switch (fmtClass)
174			{
175				case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
176				case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
177				case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
178					glClearBufferfv(GL_COLOR, 0, color.getPtr());
179					break;
180
181				case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
182					glClearBufferuiv(GL_COLOR, 0, color.cast<deUint32>().getPtr());
183					break;
184
185				case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
186					glClearBufferiv(GL_COLOR, 0, color.cast<int>().getPtr());
187					break;
188
189				default:
190					DE_ASSERT(DE_FALSE);
191			}
192		}
193
194		// Read results from renderbuffer.
195		readPixels(dst, 0, 0, m_width, m_height, fboFormat, fmtInfo.lookupScale, fmtInfo.lookupBias);
196		checkError();
197	}
198
199private:
200	const int			m_width;
201	const int			m_height;
202};
203
204class FboColorMultiTex2DCase : public FboColorbufferCase
205{
206public:
207	FboColorMultiTex2DCase (Context& context, const char* name, const char* description, deUint32 tex0Fmt, const IVec2& tex0Size, deUint32 tex1Fmt, const IVec2& tex1Size)
208		: FboColorbufferCase	(context, name, description, tex0Fmt)
209		, m_tex0Fmt				(tex0Fmt)
210		, m_tex1Fmt				(tex1Fmt)
211		, m_tex0Size			(tex0Size)
212		, m_tex1Size			(tex1Size)
213	{
214	}
215
216protected:
217	void preCheck (void)
218	{
219		checkFormatSupport(m_tex0Fmt);
220		checkFormatSupport(m_tex1Fmt);
221	}
222
223	void render (tcu::Surface& dst)
224	{
225		tcu::TextureFormat		texFmt0			= glu::mapGLInternalFormat(m_tex0Fmt);
226		tcu::TextureFormat		texFmt1			= glu::mapGLInternalFormat(m_tex1Fmt);
227		tcu::TextureFormatInfo	fmtInfo0		= tcu::getTextureFormatInfo(texFmt0);
228		tcu::TextureFormatInfo	fmtInfo1		= tcu::getTextureFormatInfo(texFmt1);
229
230		Texture2DShader			texToFbo0Shader	(DataTypes() << glu::TYPE_SAMPLER_2D, getFragmentOutputType(texFmt0), fmtInfo0.valueMax-fmtInfo0.valueMin, fmtInfo0.valueMin);
231		Texture2DShader			texToFbo1Shader	(DataTypes() << glu::TYPE_SAMPLER_2D, getFragmentOutputType(texFmt1), fmtInfo1.valueMax-fmtInfo1.valueMin, fmtInfo1.valueMin);
232		Texture2DShader			multiTexShader	(DataTypes() << glu::getSampler2DType(texFmt0) << glu::getSampler2DType(texFmt1), glu::TYPE_FLOAT_VEC4);
233
234		deUint32				texToFbo0ShaderID = getCurrentContext()->createProgram(&texToFbo0Shader);
235		deUint32				texToFbo1ShaderID = getCurrentContext()->createProgram(&texToFbo1Shader);
236		deUint32				multiTexShaderID  = getCurrentContext()->createProgram(&multiTexShader);
237
238		// Setup shaders
239		multiTexShader.setTexScaleBias(0, fmtInfo0.lookupScale * 0.5f, fmtInfo0.lookupBias * 0.5f);
240		multiTexShader.setTexScaleBias(1, fmtInfo1.lookupScale * 0.5f, fmtInfo1.lookupBias * 0.5f);
241		texToFbo0Shader.setUniforms(*getCurrentContext(), texToFbo0ShaderID);
242		texToFbo1Shader.setUniforms(*getCurrentContext(), texToFbo1ShaderID);
243		multiTexShader.setUniforms (*getCurrentContext(), multiTexShaderID);
244
245		// Framebuffers.
246		deUint32				fbo0, fbo1;
247		deUint32				tex0, tex1;
248
249		for (int ndx = 0; ndx < 2; ndx++)
250		{
251			glu::TransferFormat		transferFmt		= glu::getTransferFormat(ndx ? texFmt1 : texFmt0);
252			deUint32				format			= ndx ? m_tex1Fmt : m_tex0Fmt;
253			bool					isFilterable	= glu::isGLInternalColorFormatFilterable(format);
254			const IVec2&			size			= ndx ? m_tex1Size : m_tex0Size;
255			deUint32&				fbo				= ndx ? fbo1 : fbo0;
256			deUint32&				tex				= ndx ? tex1 : tex0;
257
258			glGenFramebuffers(1, &fbo);
259			glGenTextures(1, &tex);
260
261			glBindTexture(GL_TEXTURE_2D, tex);
262			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
263			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
264			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	isFilterable ? GL_LINEAR : GL_NEAREST);
265			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	isFilterable ? GL_LINEAR : GL_NEAREST);
266			glTexImage2D(GL_TEXTURE_2D, 0, format, size.x(), size.y(), 0, transferFmt.format, transferFmt.dataType, DE_NULL);
267
268			glBindFramebuffer(GL_FRAMEBUFFER, fbo);
269			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
270			checkError();
271			checkFramebufferStatus(GL_FRAMEBUFFER);
272		}
273
274		// Render textures to both framebuffers.
275		for (int ndx = 0; ndx < 2; ndx++)
276		{
277			const deUint32		format		= GL_RGBA;
278			const deUint32		dataType	= GL_UNSIGNED_BYTE;
279			const int			texW		= 128;
280			const int			texH		= 128;
281			deUint32			tmpTex		= 0;
282			deUint32			fbo			= ndx ? fbo1 : fbo0;
283			const IVec2&		viewport	= ndx ? m_tex1Size : m_tex0Size;
284			tcu::TextureLevel	data		(glu::mapGLTransferFormat(format, dataType), texW, texH, 1);
285
286			if (ndx == 0)
287				tcu::fillWithComponentGradients(data.getAccess(), Vec4(0.0f), Vec4(1.0f));
288			else
289				tcu::fillWithGrid(data.getAccess(), 8, Vec4(0.2f, 0.7f, 0.1f, 1.0f), Vec4(0.7f, 0.1f, 0.5f, 0.8f));
290
291			glGenTextures(1, &tmpTex);
292			glBindTexture(GL_TEXTURE_2D, tmpTex);
293			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
294			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
295			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	GL_LINEAR);
296			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	GL_LINEAR);
297			glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr());
298
299			glBindFramebuffer(GL_FRAMEBUFFER, fbo);
300			glViewport(0, 0, viewport.x(), viewport.y());
301			sglr::drawQuad(*getCurrentContext(), ndx ? texToFbo1ShaderID : texToFbo0ShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
302		}
303
304		// Render to framebuffer.
305		glBindFramebuffer(GL_FRAMEBUFFER, 0);
306		glViewport(0, 0, getWidth(), getHeight());
307		glActiveTexture(GL_TEXTURE0);
308		glBindTexture(GL_TEXTURE_2D, tex0);
309		glActiveTexture(GL_TEXTURE1);
310		glBindTexture(GL_TEXTURE_2D, tex1);
311		sglr::drawQuad(*getCurrentContext(), multiTexShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
312
313		readPixels(dst, 0, 0, getWidth(), getHeight());
314	}
315
316private:
317	deUint32		m_tex0Fmt;
318	deUint32		m_tex1Fmt;
319	IVec2			m_tex0Size;
320	IVec2			m_tex1Size;
321};
322
323class FboColorTexCubeCase : public FboColorbufferCase
324{
325public:
326	FboColorTexCubeCase			(Context& context, const char* name, const char* description, deUint32 texFmt, const IVec2& texSize)
327		: FboColorbufferCase	(context, name, description, texFmt)
328		, m_texSize				(texSize)
329	{
330	}
331
332protected:
333	void preCheck (void)
334	{
335		checkFormatSupport(m_format);
336	}
337
338	void render (tcu::Surface& dst)
339	{
340		static const deUint32 cubeGLFaces[] =
341		{
342			GL_TEXTURE_CUBE_MAP_POSITIVE_X,
343			GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
344			GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
345			GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
346			GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
347			GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
348		};
349
350		static const tcu::CubeFace cubeTexFaces[] =
351		{
352			tcu::CUBEFACE_POSITIVE_X,
353			tcu::CUBEFACE_POSITIVE_Y,
354			tcu::CUBEFACE_POSITIVE_Z,
355			tcu::CUBEFACE_NEGATIVE_X,
356			tcu::CUBEFACE_NEGATIVE_Y,
357			tcu::CUBEFACE_NEGATIVE_Z
358		};
359
360		de::Random				rnd					(deStringHash(getName()) ^ 0x9eef603d);
361		tcu::TextureFormat		texFmt				= glu::mapGLInternalFormat(m_format);
362		tcu::TextureFormatInfo	fmtInfo				= tcu::getTextureFormatInfo(texFmt);
363
364		Texture2DShader			texToFboShader		(DataTypes() << glu::TYPE_SAMPLER_2D, getFragmentOutputType(texFmt), fmtInfo.valueMax-fmtInfo.valueMin, fmtInfo.valueMin);
365		TextureCubeShader		cubeTexShader		(glu::getSamplerCubeType(texFmt), glu::TYPE_FLOAT_VEC4);
366
367		deUint32				texToFboShaderID	= getCurrentContext()->createProgram(&texToFboShader);
368		deUint32				cubeTexShaderID		= getCurrentContext()->createProgram(&cubeTexShader);
369
370		// Setup shaders
371		texToFboShader.setUniforms(*getCurrentContext(), texToFboShaderID);
372		cubeTexShader.setTexScaleBias(fmtInfo.lookupScale, fmtInfo.lookupBias);
373
374		// Framebuffers.
375		std::vector<deUint32>	fbos;
376		deUint32				tex;
377
378		{
379			glu::TransferFormat		transferFmt		= glu::getTransferFormat(texFmt);
380			bool					isFilterable	= glu::isGLInternalColorFormatFilterable(m_format);
381			const IVec2&			size			= m_texSize;
382
383
384			glGenTextures(1, &tex);
385
386			glBindTexture(GL_TEXTURE_CUBE_MAP,		tex);
387			glTexParameteri(GL_TEXTURE_CUBE_MAP,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
388			glTexParameteri(GL_TEXTURE_CUBE_MAP,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
389			glTexParameteri(GL_TEXTURE_CUBE_MAP,	GL_TEXTURE_MIN_FILTER,	isFilterable ? GL_LINEAR : GL_NEAREST);
390			glTexParameteri(GL_TEXTURE_CUBE_MAP,	GL_TEXTURE_MAG_FILTER,	isFilterable ? GL_LINEAR : GL_NEAREST);
391
392			// Generate an image and FBO for each cube face
393			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cubeGLFaces); ndx++)
394				glTexImage2D(cubeGLFaces[ndx], 0, m_format, size.x(), size.y(), 0, transferFmt.format, transferFmt.dataType, DE_NULL);
395			checkError();
396
397			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cubeGLFaces); ndx++)
398			{
399				deUint32			layerFbo;
400
401				glGenFramebuffers(1, &layerFbo);
402				glBindFramebuffer(GL_FRAMEBUFFER, layerFbo);
403				glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, cubeGLFaces[ndx], tex, 0);
404				checkError();
405				checkFramebufferStatus(GL_FRAMEBUFFER);
406
407				fbos.push_back(layerFbo);
408			}
409		}
410
411		// Render test images to random cube faces
412		std::vector<int> order;
413
414		for (size_t n = 0; n < fbos.size(); n++)
415			order.push_back((int)n);
416		rnd.shuffle(order.begin(), order.end());
417
418		DE_ASSERT(order.size() >= 4);
419		for (int ndx = 0; ndx < 4; ndx++)
420		{
421			const int			face		= order[ndx];
422			const deUint32		format		= GL_RGBA;
423			const deUint32		dataType	= GL_UNSIGNED_BYTE;
424			const int			texW		= 128;
425			const int			texH		= 128;
426			deUint32			tmpTex		= 0;
427			const deUint32		fbo			= fbos[face];
428			const IVec2&		viewport	= m_texSize;
429			tcu::TextureLevel	data		(glu::mapGLTransferFormat(format, dataType), texW, texH, 1);
430
431			tcu::fillWithGrid(data.getAccess(), 8, generateRandomColor(rnd), Vec4(0.0f));
432
433			glGenTextures(1, &tmpTex);
434			glBindTexture(GL_TEXTURE_2D, tmpTex);
435			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
436			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
437			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	GL_LINEAR);
438			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	GL_LINEAR);
439			glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr());
440
441			glBindFramebuffer(GL_FRAMEBUFFER, fbo);
442			glViewport(0, 0, viewport.x(), viewport.y());
443			sglr::drawQuad(*getCurrentContext(), texToFboShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
444			checkError();
445
446			// Render to framebuffer
447			{
448				const Vec3		p0	= Vec3(float(ndx % 2) - 1.0f, float(ndx / 2) - 1.0f, 0.0f);
449				const Vec3		p1	= p0 + Vec3(1.0f, 1.0f, 0.0f);
450
451				glBindFramebuffer(GL_FRAMEBUFFER, 0);
452				glViewport(0, 0, getWidth(), getHeight());
453
454				glActiveTexture(GL_TEXTURE0);
455				glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
456
457				cubeTexShader.setFace(cubeTexFaces[face]);
458				cubeTexShader.setUniforms(*getCurrentContext(), cubeTexShaderID);
459
460				sglr::drawQuad(*getCurrentContext(), cubeTexShaderID, p0, p1);
461				checkError();
462			}
463		}
464
465		readPixels(dst, 0, 0, getWidth(), getHeight());
466	}
467
468private:
469	IVec2			m_texSize;
470};
471
472class FboColorTex2DArrayCase : public FboColorbufferCase
473{
474public:
475	FboColorTex2DArrayCase (Context& context, const char* name, const char* description, deUint32 texFmt, const IVec3& texSize)
476		: FboColorbufferCase	(context, name, description, texFmt)
477		, m_texSize				(texSize)
478	{
479	}
480
481protected:
482	void preCheck (void)
483	{
484		checkFormatSupport(m_format);
485	}
486
487	void render (tcu::Surface& dst)
488	{
489		de::Random				rnd					(deStringHash(getName()) ^ 0xed607a89);
490		tcu::TextureFormat		texFmt				= glu::mapGLInternalFormat(m_format);
491		tcu::TextureFormatInfo	fmtInfo				= tcu::getTextureFormatInfo(texFmt);
492
493		Texture2DShader			texToFboShader		(DataTypes() << glu::TYPE_SAMPLER_2D, getFragmentOutputType(texFmt), fmtInfo.valueMax-fmtInfo.valueMin, fmtInfo.valueMin);
494		Texture2DArrayShader	arrayTexShader		(glu::getSampler2DArrayType(texFmt), glu::TYPE_FLOAT_VEC4);
495
496		deUint32				texToFboShaderID	= getCurrentContext()->createProgram(&texToFboShader);
497		deUint32				arrayTexShaderID	= getCurrentContext()->createProgram(&arrayTexShader);
498
499		// Setup textures
500		texToFboShader.setUniforms(*getCurrentContext(), texToFboShaderID);
501		arrayTexShader.setTexScaleBias(fmtInfo.lookupScale, fmtInfo.lookupBias);
502
503		// Framebuffers.
504		std::vector<deUint32>	fbos;
505		deUint32				tex;
506
507		{
508			glu::TransferFormat		transferFmt		= glu::getTransferFormat(texFmt);
509			bool					isFilterable	= glu::isGLInternalColorFormatFilterable(m_format);
510			const IVec3&			size			= m_texSize;
511
512
513			glGenTextures(1, &tex);
514
515			glBindTexture(GL_TEXTURE_2D_ARRAY,		tex);
516			glTexParameteri(GL_TEXTURE_2D_ARRAY,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
517			glTexParameteri(GL_TEXTURE_2D_ARRAY,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
518			glTexParameteri(GL_TEXTURE_2D_ARRAY,	GL_TEXTURE_WRAP_R,		GL_CLAMP_TO_EDGE);
519			glTexParameteri(GL_TEXTURE_2D_ARRAY,	GL_TEXTURE_MIN_FILTER,	isFilterable ? GL_LINEAR : GL_NEAREST);
520			glTexParameteri(GL_TEXTURE_2D_ARRAY,	GL_TEXTURE_MAG_FILTER,	isFilterable ? GL_LINEAR : GL_NEAREST);
521			glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, m_format, size.x(), size.y(), size.z(), 0, transferFmt.format, transferFmt.dataType, DE_NULL);
522
523			// Generate an FBO for each layer
524			for (int ndx = 0; ndx < m_texSize.z(); ndx++)
525			{
526				deUint32			layerFbo;
527
528				glGenFramebuffers(1, &layerFbo);
529				glBindFramebuffer(GL_FRAMEBUFFER, layerFbo);
530				glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, ndx);
531				checkError();
532				checkFramebufferStatus(GL_FRAMEBUFFER);
533
534				fbos.push_back(layerFbo);
535			}
536		}
537
538		// Render test images to random texture layers
539		std::vector<int>		order;
540
541		for (size_t n = 0; n < fbos.size(); n++)
542			order.push_back((int)n);
543		rnd.shuffle(order.begin(), order.end());
544
545		for (size_t ndx = 0; ndx < order.size(); ndx++)
546		{
547			const int			layer		= order[ndx];
548			const deUint32		format		= GL_RGBA;
549			const deUint32		dataType	= GL_UNSIGNED_BYTE;
550			const int			texW		= 128;
551			const int			texH		= 128;
552			deUint32			tmpTex		= 0;
553			const deUint32		fbo			= fbos[layer];
554			const IVec3&		viewport	= m_texSize;
555			tcu::TextureLevel	data		(glu::mapGLTransferFormat(format, dataType), texW, texH, 1);
556
557			tcu::fillWithGrid(data.getAccess(), 8, generateRandomColor(rnd), Vec4(0.0f));
558
559			glGenTextures(1, &tmpTex);
560			glBindTexture(GL_TEXTURE_2D, tmpTex);
561			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
562			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
563			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	GL_LINEAR);
564			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	GL_LINEAR);
565			glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr());
566
567			glBindFramebuffer(GL_FRAMEBUFFER, fbo);
568			glViewport(0, 0, viewport.x(), viewport.y());
569			sglr::drawQuad(*getCurrentContext(), texToFboShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
570			checkError();
571
572			// Render to framebuffer
573			{
574				const Vec3		p0	= Vec3(float(ndx % 2) - 1.0f, float(ndx / 2) - 1.0f, 0.0f);
575				const Vec3		p1	= p0 + Vec3(1.0f, 1.0f, 0.0f);
576
577				glBindFramebuffer(GL_FRAMEBUFFER, 0);
578				glViewport(0, 0, getWidth(), getHeight());
579
580				glActiveTexture(GL_TEXTURE0);
581				glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
582
583				arrayTexShader.setLayer(layer);
584				arrayTexShader.setUniforms(*getCurrentContext(), arrayTexShaderID);
585
586				sglr::drawQuad(*getCurrentContext(), arrayTexShaderID, p0, p1);
587				checkError();
588			}
589		}
590
591		readPixels(dst, 0, 0, getWidth(), getHeight());
592	}
593
594private:
595	IVec3			m_texSize;
596};
597
598class FboColorTex3DCase : public FboColorbufferCase
599{
600public:
601	FboColorTex3DCase (Context& context, const char* name, const char* description, deUint32 texFmt, const IVec3& texSize)
602		: FboColorbufferCase	(context, name, description, texFmt)
603		, m_texSize				(texSize)
604	{
605	}
606
607protected:
608	void preCheck (void)
609	{
610		checkFormatSupport(m_format);
611	}
612
613	void render (tcu::Surface& dst)
614	{
615		de::Random				rnd				(deStringHash(getName()) ^ 0x74d947b2);
616		tcu::TextureFormat		texFmt			= glu::mapGLInternalFormat(m_format);
617		tcu::TextureFormatInfo	fmtInfo			= tcu::getTextureFormatInfo(texFmt);
618
619		Texture2DShader			texToFboShader	(DataTypes() << glu::TYPE_SAMPLER_2D, getFragmentOutputType(texFmt), fmtInfo.valueMax-fmtInfo.valueMin, fmtInfo.valueMin);
620		Texture3DShader			tdTexShader		(glu::getSampler3DType(texFmt), glu::TYPE_FLOAT_VEC4);
621
622		deUint32				texToFboShaderID= getCurrentContext()->createProgram(&texToFboShader);
623		deUint32				tdTexShaderID	= getCurrentContext()->createProgram(&tdTexShader);
624
625		// Setup shaders
626		texToFboShader.setUniforms(*getCurrentContext(), texToFboShaderID);
627		tdTexShader.setTexScaleBias(fmtInfo.lookupScale, fmtInfo.lookupBias);
628
629		// Framebuffers.
630		std::vector<deUint32>	fbos;
631		deUint32				tex;
632
633		{
634			glu::TransferFormat		transferFmt		= glu::getTransferFormat(texFmt);
635			const IVec3&			size			= m_texSize;
636
637			glGenTextures(1, &tex);
638
639			glBindTexture(GL_TEXTURE_3D,		tex);
640			glTexParameteri(GL_TEXTURE_3D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
641			glTexParameteri(GL_TEXTURE_3D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
642			glTexParameteri(GL_TEXTURE_3D,	GL_TEXTURE_WRAP_R,		GL_CLAMP_TO_EDGE);
643			glTexParameteri(GL_TEXTURE_3D,	GL_TEXTURE_MIN_FILTER,	GL_NEAREST);
644			glTexParameteri(GL_TEXTURE_3D,	GL_TEXTURE_MAG_FILTER,	GL_NEAREST);
645			glTexImage3D(GL_TEXTURE_3D, 0, m_format, size.x(), size.y(), size.z(), 0, transferFmt.format, transferFmt.dataType, DE_NULL);
646
647			// Generate an FBO for each layer
648			for (int ndx = 0; ndx < m_texSize.z(); ndx++)
649			{
650				deUint32			layerFbo;
651
652				glGenFramebuffers(1, &layerFbo);
653				glBindFramebuffer(GL_FRAMEBUFFER, layerFbo);
654				glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, ndx);
655				checkError();
656				checkFramebufferStatus(GL_FRAMEBUFFER);
657
658				fbos.push_back(layerFbo);
659			}
660		}
661
662		// Render test images to random texture layers
663		std::vector<int> order;
664
665		for (size_t n = 0; n < fbos.size(); n++)
666			order.push_back((int)n);
667		rnd.shuffle(order.begin(), order.end());
668
669		for (size_t ndx = 0; ndx < order.size(); ndx++)
670		{
671			const int			layer		= order[ndx];
672			const deUint32		format		= GL_RGBA;
673			const deUint32		dataType	= GL_UNSIGNED_BYTE;
674			const int			texW		= 128;
675			const int			texH		= 128;
676			deUint32			tmpTex		= 0;
677			const deUint32		fbo			= fbos[layer];
678			const IVec3&		viewport	= m_texSize;
679			tcu::TextureLevel	data		(glu::mapGLTransferFormat(format, dataType), texW, texH, 1);
680
681			tcu::fillWithGrid(data.getAccess(), 8, generateRandomColor(rnd), Vec4(0.0f));
682
683			glGenTextures(1, &tmpTex);
684			glBindTexture(GL_TEXTURE_2D, tmpTex);
685			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
686			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
687			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	GL_LINEAR);
688			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	GL_LINEAR);
689			glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr());
690
691			glBindFramebuffer(GL_FRAMEBUFFER, fbo);
692			glViewport(0, 0, viewport.x(), viewport.y());
693			sglr::drawQuad(*getCurrentContext() , texToFboShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
694			checkError();
695
696			// Render to framebuffer
697			{
698				const Vec3		p0	= Vec3(float(ndx % 2) - 1.0f, float(ndx / 2) - 1.0f, 0.0f);
699				const Vec3		p1	= p0 + Vec3(1.0f, 1.0f, 0.0f);
700
701				glBindFramebuffer(GL_FRAMEBUFFER, 0);
702				glViewport(0, 0, getWidth(), getHeight());
703
704				glActiveTexture(GL_TEXTURE0);
705				glBindTexture(GL_TEXTURE_3D, tex);
706
707				tdTexShader.setDepth(float(layer) / float(m_texSize.z()-1));
708				tdTexShader.setUniforms(*getCurrentContext(), tdTexShaderID);
709
710				sglr::drawQuad(*getCurrentContext(), tdTexShaderID, p0, p1);
711				checkError();
712			}
713		}
714
715		readPixels(dst, 0, 0, getWidth(), getHeight());
716	}
717
718private:
719	IVec3			m_texSize;
720};
721
722class FboBlendCase : public FboColorbufferCase
723{
724public:
725	FboBlendCase (Context& context, const char* name, const char* desc, deUint32 format, IVec2 size, deUint32 funcRGB, deUint32 funcAlpha, deUint32 srcRGB, deUint32 dstRGB, deUint32 srcAlpha, deUint32 dstAlpha)
726		: FboColorbufferCase	(context, name, desc, format)
727		, m_size				(size)
728		, m_funcRGB				(funcRGB)
729		, m_funcAlpha			(funcAlpha)
730		, m_srcRGB				(srcRGB)
731		, m_dstRGB				(dstRGB)
732		, m_srcAlpha			(srcAlpha)
733		, m_dstAlpha			(dstAlpha)
734	{
735	}
736
737protected:
738	void preCheck (void)
739	{
740		checkFormatSupport(m_format);
741	}
742
743	void render (tcu::Surface& dst)
744	{
745		// \note Assumes floating-point or fixed-point format.
746		tcu::TextureFormat			fboFmt			= glu::mapGLInternalFormat(m_format);
747		Texture2DShader				texShader		(DataTypes() << glu::TYPE_SAMPLER_2D, glu::TYPE_FLOAT_VEC4);
748		GradientShader				gradShader		(glu::TYPE_FLOAT_VEC4);
749		deUint32					texShaderID		= getCurrentContext()->createProgram(&texShader);
750		deUint32					gradShaderID	= getCurrentContext()->createProgram(&gradShader);
751		deUint32					fbo				= 0;
752		deUint32					rbo				= 0;
753
754		// Setup shaders
755		texShader.setUniforms (*getCurrentContext(), texShaderID);
756		gradShader.setGradient(*getCurrentContext(), gradShaderID, tcu::Vec4(0.0f), tcu::Vec4(1.0f));
757
758		glGenFramebuffers(1, &fbo);
759		glGenRenderbuffers(1, &rbo);
760
761		glBindRenderbuffer(GL_RENDERBUFFER, rbo);
762		glRenderbufferStorage(GL_RENDERBUFFER, m_format, m_size.x(), m_size.y());
763		checkError();
764
765		glBindFramebuffer(GL_FRAMEBUFFER, fbo);
766		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
767		checkError();
768		checkFramebufferStatus(GL_FRAMEBUFFER);
769
770		glViewport(0, 0, m_size.x(), m_size.y());
771
772		// Fill framebuffer with grid pattern.
773		{
774			const deUint32		format		= GL_RGBA;
775			const deUint32		dataType	= GL_UNSIGNED_BYTE;
776			const int			texW		= 128;
777			const int			texH		= 128;
778			deUint32			gridTex		= 0;
779			tcu::TextureLevel	data		(glu::mapGLTransferFormat(format, dataType), texW, texH, 1);
780
781			tcu::fillWithGrid(data.getAccess(), 8, Vec4(0.2f, 0.7f, 0.1f, 1.0f), Vec4(0.7f, 0.1f, 0.5f, 0.8f));
782
783			glGenTextures(1, &gridTex);
784			glBindTexture(GL_TEXTURE_2D, gridTex);
785			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
786			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
787			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	GL_LINEAR);
788			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	GL_LINEAR);
789			glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr());
790
791			sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
792		}
793
794		// Setup blend.
795		glEnable(GL_BLEND);
796		glBlendEquationSeparate(m_funcRGB, m_funcAlpha);
797		glBlendFuncSeparate(m_srcRGB, m_dstRGB, m_srcAlpha, m_dstAlpha);
798
799		// Render gradient with blend.
800		sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
801
802		readPixels(dst, 0, 0, m_size.x(), m_size.y(), fboFmt, Vec4(1.0f), Vec4(0.0f));
803	}
804
805private:
806	IVec2		m_size;
807	deUint32	m_funcRGB;
808	deUint32	m_funcAlpha;
809	deUint32	m_srcRGB;
810	deUint32	m_dstRGB;
811	deUint32	m_srcAlpha;
812	deUint32	m_dstAlpha;
813};
814
815FboColorTests::FboColorTests (Context& context)
816	: TestCaseGroup(context, "color", "Colorbuffer tests")
817{
818}
819
820FboColorTests::~FboColorTests (void)
821{
822}
823
824void FboColorTests::init (void)
825{
826	static const deUint32 colorFormats[] =
827	{
828		// RGBA formats
829		GL_RGBA32I,
830		GL_RGBA32UI,
831		GL_RGBA16I,
832		GL_RGBA16UI,
833		GL_RGBA8,
834		GL_RGBA8I,
835		GL_RGBA8UI,
836		GL_SRGB8_ALPHA8,
837		GL_RGB10_A2,
838		GL_RGB10_A2UI,
839		GL_RGBA4,
840		GL_RGB5_A1,
841
842		// RGB formats
843		GL_RGB8,
844		GL_RGB565,
845
846		// RG formats
847		GL_RG32I,
848		GL_RG32UI,
849		GL_RG16I,
850		GL_RG16UI,
851		GL_RG8,
852		GL_RG8I,
853		GL_RG8UI,
854
855		// R formats
856		GL_R32I,
857		GL_R32UI,
858		GL_R16I,
859		GL_R16UI,
860		GL_R8,
861		GL_R8I,
862		GL_R8UI,
863
864		// GL_EXT_color_buffer_float
865		GL_RGBA32F,
866		GL_RGBA16F,
867		GL_R11F_G11F_B10F,
868		GL_RG32F,
869		GL_RG16F,
870		GL_R32F,
871		GL_R16F,
872
873		// GL_EXT_color_buffer_half_float
874		GL_RGB16F
875	};
876
877	// .clear
878	{
879		tcu::TestCaseGroup* clearGroup = new tcu::TestCaseGroup(m_testCtx, "clear", "Color clears");
880		addChild(clearGroup);
881
882		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(colorFormats); ndx++)
883			clearGroup->addChild(new FboColorClearCase(m_context, getFormatName(colorFormats[ndx]), "", colorFormats[ndx], 129, 117));
884	}
885
886	// .tex2d
887	{
888		tcu::TestCaseGroup* tex2DGroup = new tcu::TestCaseGroup(m_testCtx, "tex2d", "Texture 2D tests");
889		addChild(tex2DGroup);
890
891		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
892			tex2DGroup->addChild(new FboColorMultiTex2DCase(m_context, getFormatName(colorFormats[fmtNdx]), "",
893															colorFormats[fmtNdx], IVec2(129, 117),
894															colorFormats[fmtNdx], IVec2(99, 128)));
895	}
896
897	// .texcube
898	{
899		tcu::TestCaseGroup* texCubeGroup = new tcu::TestCaseGroup(m_testCtx, "texcube", "Texture cube map tests");
900		addChild(texCubeGroup);
901
902		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
903			texCubeGroup->addChild(new FboColorTexCubeCase(m_context, getFormatName(colorFormats[fmtNdx]), "",
904														   colorFormats[fmtNdx], IVec2(128, 128)));
905	}
906
907	// .tex2darray
908	{
909		tcu::TestCaseGroup* tex2DArrayGroup = new tcu::TestCaseGroup(m_testCtx, "tex2darray", "Texture 2D array tests");
910		addChild(tex2DArrayGroup);
911
912		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
913			tex2DArrayGroup->addChild(new FboColorTex2DArrayCase(m_context, getFormatName(colorFormats[fmtNdx]), "",
914																 colorFormats[fmtNdx], IVec3(128, 128, 5)));
915	}
916
917	// .tex3d
918	{
919		tcu::TestCaseGroup* tex3DGroup = new tcu::TestCaseGroup(m_testCtx, "tex3d", "Texture 3D tests");
920		addChild(tex3DGroup);
921
922		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
923			tex3DGroup->addChild(new FboColorTex3DCase(m_context, getFormatName(colorFormats[fmtNdx]), "",
924													   colorFormats[fmtNdx], IVec3(128, 128, 5)));
925	}
926
927	// .blend
928	{
929		tcu::TestCaseGroup* blendGroup = new tcu::TestCaseGroup(m_testCtx, "blend", "Blending tests");
930		addChild(blendGroup);
931
932		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
933		{
934			deUint32					format		= colorFormats[fmtNdx];
935			tcu::TextureFormat			texFmt		= glu::mapGLInternalFormat(format);
936			tcu::TextureChannelClass	fmtClass	= tcu::getTextureChannelClass(texFmt.type);
937			string						fmtName		= getFormatName(format);
938
939			if (texFmt.type	== tcu::TextureFormat::FLOAT				||
940				fmtClass	== tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER	||
941				fmtClass	== tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
942				continue; // Blending is not supported.
943
944			blendGroup->addChild(new FboBlendCase(m_context, (fmtName + "_src_over").c_str(), "", format, IVec2(127, 111), GL_FUNC_ADD, GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE));
945		}
946	}
947}
948
949} // Functional
950} // gles3
951} // deqp
952