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 
38 namespace deqp
39 {
40 namespace gles3
41 {
42 namespace Functional
43 {
44 
45 using std::string;
46 using tcu::Vec2;
47 using tcu::Vec3;
48 using tcu::Vec4;
49 using tcu::IVec2;
50 using tcu::IVec3;
51 using tcu::IVec4;
52 using tcu::UVec4;
53 using tcu::TestLog;
54 using namespace FboTestUtil;
55 
56 const tcu::RGBA MIN_THRESHOLD(12, 12, 12, 12);
57 
58 template <int Size>
59 static 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 
generateRandomColor(de::Random & random)67 static 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 
78 class FboColorbufferCase : public FboTestCase
79 {
80 public:
FboColorbufferCase(Context & context,const char * name,const char * desc,const deUint32 format)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 
compare(const tcu::Surface & reference,const tcu::Surface & result)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 
96 protected:
97 	const deUint32	m_format;
98 };
99 
100 class FboColorClearCase : public FboColorbufferCase
101 {
102 public:
FboColorClearCase(Context & context,const char * name,const char * desc,deUint32 format,int width,int height)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 
110 protected:
preCheck(void)111 	void preCheck (void)
112 	{
113 		checkFormatSupport(m_format);
114 	}
115 
render(tcu::Surface & dst)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 
199 private:
200 	const int			m_width;
201 	const int			m_height;
202 };
203 
204 class FboColorMultiTex2DCase : public FboColorbufferCase
205 {
206 public:
FboColorMultiTex2DCase(Context & context,const char * name,const char * description,deUint32 tex0Fmt,const IVec2 & tex0Size,deUint32 tex1Fmt,const IVec2 & tex1Size)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 
216 protected:
preCheck(void)217 	void preCheck (void)
218 	{
219 		checkFormatSupport(m_tex0Fmt);
220 		checkFormatSupport(m_tex1Fmt);
221 	}
222 
render(tcu::Surface & dst)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 
316 private:
317 	deUint32		m_tex0Fmt;
318 	deUint32		m_tex1Fmt;
319 	IVec2			m_tex0Size;
320 	IVec2			m_tex1Size;
321 };
322 
323 class FboColorTexCubeCase : public FboColorbufferCase
324 {
325 public:
FboColorTexCubeCase(Context & context,const char * name,const char * description,deUint32 texFmt,const IVec2 & texSize)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 
332 protected:
preCheck(void)333 	void preCheck (void)
334 	{
335 		checkFormatSupport(m_format);
336 	}
337 
render(tcu::Surface & dst)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 
468 private:
469 	IVec2			m_texSize;
470 };
471 
472 class FboColorTex2DArrayCase : public FboColorbufferCase
473 {
474 public:
FboColorTex2DArrayCase(Context & context,const char * name,const char * description,deUint32 texFmt,const IVec3 & texSize)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 
481 protected:
preCheck(void)482 	void preCheck (void)
483 	{
484 		checkFormatSupport(m_format);
485 	}
486 
render(tcu::Surface & dst)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 
594 private:
595 	IVec3			m_texSize;
596 };
597 
598 class FboColorTex3DCase : public FboColorbufferCase
599 {
600 public:
FboColorTex3DCase(Context & context,const char * name,const char * description,deUint32 texFmt,const IVec3 & texSize)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 
607 protected:
preCheck(void)608 	void preCheck (void)
609 	{
610 		checkFormatSupport(m_format);
611 	}
612 
render(tcu::Surface & dst)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 
718 private:
719 	IVec3			m_texSize;
720 };
721 
722 class FboBlendCase : public FboColorbufferCase
723 {
724 public:
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)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 
737 protected:
preCheck(void)738 	void preCheck (void)
739 	{
740 		checkFormatSupport(m_format);
741 	}
742 
render(tcu::Surface & dst)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 
805 private:
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 
815 class FboRepeatedClearSampleTex2DCase : public FboColorbufferCase
816 {
817 public:
FboRepeatedClearSampleTex2DCase(Context & context,const char * name,const char * desc,deUint32 format)818 	FboRepeatedClearSampleTex2DCase (Context& context, const char* name, const char* desc, deUint32 format)
819 		: FboColorbufferCase(context, name, desc, format)
820 	{
821 	}
822 
823 protected:
preCheck(void)824 	void preCheck (void)
825 	{
826 		checkFormatSupport(m_format);
827 	}
828 
render(tcu::Surface & dst)829 	void render (tcu::Surface& dst)
830 	{
831 		const tcu::TextureFormat		fboFormat		= glu::mapGLInternalFormat(m_format);
832 		const tcu::TextureFormatInfo	fmtInfo			= tcu::getTextureFormatInfo(fboFormat);
833 		const int						numRowsCols		= 4;
834 		const int						cellSize		= 16;
835 		const int						fboSizes[]		= { cellSize, cellSize*numRowsCols };
836 
837 		Texture2DShader					fboBlitShader	(DataTypes() << glu::getSampler2DType(fboFormat), getFragmentOutputType(fboFormat), Vec4(1.0f), Vec4(0.0f));
838 		const deUint32					fboBlitShaderID	= getCurrentContext()->createProgram(&fboBlitShader);
839 
840 		de::Random						rnd				(18169662);
841 		deUint32						fbos[]			= { 0, 0 };
842 		deUint32						textures[]		= { 0, 0 };
843 
844 		glGenFramebuffers(2, &fbos[0]);
845 		glGenTextures(2, &textures[0]);
846 
847 		for (int fboNdx = 0; fboNdx < DE_LENGTH_OF_ARRAY(fbos); fboNdx++)
848 		{
849 			glBindTexture(GL_TEXTURE_2D, textures[fboNdx]);
850 			glTexStorage2D(GL_TEXTURE_2D, 1, m_format, fboSizes[fboNdx], fboSizes[fboNdx]);
851 			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
852 			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
853 			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	GL_NEAREST);
854 			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	GL_NEAREST);
855 			checkError();
856 
857 			glBindFramebuffer(GL_FRAMEBUFFER, fbos[fboNdx]);
858 			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[fboNdx], 0);
859 			checkError();
860 			checkFramebufferStatus(GL_FRAMEBUFFER);
861 		}
862 
863 		// larger fbo bound -- clear to transparent black
864 		clearColorBuffer(fboFormat, Vec4(0.0f));
865 
866 		fboBlitShader.setUniforms(*getCurrentContext(), fboBlitShaderID);
867 		glBindTexture(GL_TEXTURE_2D, textures[0]);
868 
869 		for (int cellY = 0; cellY < numRowsCols; cellY++)
870 		for (int cellX = 0; cellX < numRowsCols; cellX++)
871 		{
872 			const Vec4	color	= randomVector<4>(rnd, fmtInfo.valueMin, fmtInfo.valueMax);
873 
874 			glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]);
875 			clearColorBuffer(fboFormat, color);
876 
877 			glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]);
878 			glViewport(cellX*cellSize, cellY*cellSize, cellSize, cellSize);
879 			sglr::drawQuad(*getCurrentContext(), fboBlitShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
880 		}
881 
882 		readPixels(dst, 0, 0, fboSizes[1], fboSizes[1], fboFormat, fmtInfo.lookupScale, fmtInfo.lookupBias);
883 		checkError();
884 	}
885 };
886 
887 class FboRepeatedClearBlitTex2DCase : public FboColorbufferCase
888 {
889 public:
FboRepeatedClearBlitTex2DCase(Context & context,const char * name,const char * desc,deUint32 format)890 	FboRepeatedClearBlitTex2DCase (Context& context, const char* name, const char* desc, deUint32 format)
891 		: FboColorbufferCase(context, name, desc, format)
892 	{
893 	}
894 
895 protected:
preCheck(void)896 	void preCheck (void)
897 	{
898 		checkFormatSupport(m_format);
899 	}
900 
render(tcu::Surface & dst)901 	void render (tcu::Surface& dst)
902 	{
903 		const tcu::TextureFormat		fboFormat		= glu::mapGLInternalFormat(m_format);
904 		const tcu::TextureFormatInfo	fmtInfo			= tcu::getTextureFormatInfo(fboFormat);
905 		const int						numRowsCols		= 4;
906 		const int						cellSize		= 16;
907 		const int						fboSizes[]		= { cellSize, cellSize*numRowsCols };
908 
909 		de::Random						rnd				(18169662);
910 		deUint32						fbos[]			= { 0, 0 };
911 		deUint32						textures[]		= { 0, 0 };
912 
913 		glGenFramebuffers(2, &fbos[0]);
914 		glGenTextures(2, &textures[0]);
915 
916 		for (int fboNdx = 0; fboNdx < DE_LENGTH_OF_ARRAY(fbos); fboNdx++)
917 		{
918 			glBindTexture(GL_TEXTURE_2D, textures[fboNdx]);
919 			glTexStorage2D(GL_TEXTURE_2D, 1, m_format, fboSizes[fboNdx], fboSizes[fboNdx]);
920 			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
921 			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
922 			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	GL_NEAREST);
923 			glTexParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	GL_NEAREST);
924 			checkError();
925 
926 			glBindFramebuffer(GL_FRAMEBUFFER, fbos[fboNdx]);
927 			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[fboNdx], 0);
928 			checkError();
929 			checkFramebufferStatus(GL_FRAMEBUFFER);
930 		}
931 
932 		// larger fbo bound -- clear to transparent black
933 		clearColorBuffer(fboFormat, Vec4(0.0f));
934 
935 		for (int cellY = 0; cellY < numRowsCols; cellY++)
936 		for (int cellX = 0; cellX < numRowsCols; cellX++)
937 		{
938 			const Vec4	color	= randomVector<4>(rnd, fmtInfo.valueMin, fmtInfo.valueMax);
939 
940 			glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]);
941 			clearColorBuffer(fboFormat, color);
942 
943 			glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
944 			glBlitFramebuffer(0, 0, cellSize, cellSize, cellX*cellSize, cellY*cellSize, (cellX+1)*cellSize, (cellY+1)*cellSize, GL_COLOR_BUFFER_BIT, GL_NEAREST);
945 		}
946 
947 		glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]);
948 		readPixels(dst, 0, 0, fboSizes[1], fboSizes[1], fboFormat, fmtInfo.lookupScale, fmtInfo.lookupBias);
949 		checkError();
950 	}
951 };
952 
953 class FboRepeatedClearBlitRboCase : public FboColorbufferCase
954 {
955 public:
FboRepeatedClearBlitRboCase(Context & context,const char * name,const char * desc,deUint32 format)956 	FboRepeatedClearBlitRboCase (Context& context, const char* name, const char* desc, deUint32 format)
957 		: FboColorbufferCase(context, name, desc, format)
958 	{
959 	}
960 
961 protected:
preCheck(void)962 	void preCheck (void)
963 	{
964 		checkFormatSupport(m_format);
965 	}
966 
render(tcu::Surface & dst)967 	void render (tcu::Surface& dst)
968 	{
969 		const tcu::TextureFormat		fboFormat		= glu::mapGLInternalFormat(m_format);
970 		const tcu::TextureFormatInfo	fmtInfo			= tcu::getTextureFormatInfo(fboFormat);
971 		const int						numRowsCols		= 4;
972 		const int						cellSize		= 16;
973 		const int						fboSizes[]		= { cellSize, cellSize*numRowsCols };
974 
975 		de::Random						rnd				(18169662);
976 		deUint32						fbos[]			= { 0, 0 };
977 		deUint32						rbos[]			= { 0, 0 };
978 
979 		glGenFramebuffers(2, &fbos[0]);
980 		glGenRenderbuffers(2, &rbos[0]);
981 
982 		for (int fboNdx = 0; fboNdx < DE_LENGTH_OF_ARRAY(fbos); fboNdx++)
983 		{
984 			glBindRenderbuffer(GL_RENDERBUFFER, rbos[fboNdx]);
985 			glRenderbufferStorage(GL_RENDERBUFFER, m_format, fboSizes[fboNdx], fboSizes[fboNdx]);
986 			checkError();
987 
988 			glBindFramebuffer(GL_FRAMEBUFFER, fbos[fboNdx]);
989 			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbos[fboNdx]);
990 			checkError();
991 			checkFramebufferStatus(GL_FRAMEBUFFER);
992 		}
993 
994 		// larger fbo bound -- clear to transparent black
995 		clearColorBuffer(fboFormat, Vec4(0.0f));
996 
997 		for (int cellY = 0; cellY < numRowsCols; cellY++)
998 		for (int cellX = 0; cellX < numRowsCols; cellX++)
999 		{
1000 			const Vec4	color	= randomVector<4>(rnd, fmtInfo.valueMin, fmtInfo.valueMax);
1001 
1002 			glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]);
1003 			clearColorBuffer(fboFormat, color);
1004 
1005 			glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
1006 			glBlitFramebuffer(0, 0, cellSize, cellSize, cellX*cellSize, cellY*cellSize, (cellX+1)*cellSize, (cellY+1)*cellSize, GL_COLOR_BUFFER_BIT, GL_NEAREST);
1007 		}
1008 
1009 		glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]);
1010 		readPixels(dst, 0, 0, fboSizes[1], fboSizes[1], fboFormat, fmtInfo.lookupScale, fmtInfo.lookupBias);
1011 		checkError();
1012 	}
1013 };
1014 
FboColorTests(Context & context)1015 FboColorTests::FboColorTests (Context& context)
1016 	: TestCaseGroup(context, "color", "Colorbuffer tests")
1017 {
1018 }
1019 
~FboColorTests(void)1020 FboColorTests::~FboColorTests (void)
1021 {
1022 }
1023 
init(void)1024 void FboColorTests::init (void)
1025 {
1026 	static const deUint32 colorFormats[] =
1027 	{
1028 		// RGBA formats
1029 		GL_RGBA32I,
1030 		GL_RGBA32UI,
1031 		GL_RGBA16I,
1032 		GL_RGBA16UI,
1033 		GL_RGBA8,
1034 		GL_RGBA8I,
1035 		GL_RGBA8UI,
1036 		GL_SRGB8_ALPHA8,
1037 		GL_RGB10_A2,
1038 		GL_RGB10_A2UI,
1039 		GL_RGBA4,
1040 		GL_RGB5_A1,
1041 
1042 		// RGB formats
1043 		GL_RGB8,
1044 		GL_RGB565,
1045 
1046 		// RG formats
1047 		GL_RG32I,
1048 		GL_RG32UI,
1049 		GL_RG16I,
1050 		GL_RG16UI,
1051 		GL_RG8,
1052 		GL_RG8I,
1053 		GL_RG8UI,
1054 
1055 		// R formats
1056 		GL_R32I,
1057 		GL_R32UI,
1058 		GL_R16I,
1059 		GL_R16UI,
1060 		GL_R8,
1061 		GL_R8I,
1062 		GL_R8UI,
1063 
1064 		// GL_EXT_color_buffer_float
1065 		GL_RGBA32F,
1066 		GL_RGBA16F,
1067 		GL_R11F_G11F_B10F,
1068 		GL_RG32F,
1069 		GL_RG16F,
1070 		GL_R32F,
1071 		GL_R16F,
1072 
1073 		// GL_EXT_color_buffer_half_float
1074 		GL_RGB16F
1075 	};
1076 
1077 	// .clear
1078 	{
1079 		tcu::TestCaseGroup* clearGroup = new tcu::TestCaseGroup(m_testCtx, "clear", "Color clears");
1080 		addChild(clearGroup);
1081 
1082 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(colorFormats); ndx++)
1083 			clearGroup->addChild(new FboColorClearCase(m_context, getFormatName(colorFormats[ndx]), "", colorFormats[ndx], 129, 117));
1084 	}
1085 
1086 	// .tex2d
1087 	{
1088 		tcu::TestCaseGroup* tex2DGroup = new tcu::TestCaseGroup(m_testCtx, "tex2d", "Texture 2D tests");
1089 		addChild(tex2DGroup);
1090 
1091 		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
1092 			tex2DGroup->addChild(new FboColorMultiTex2DCase(m_context, getFormatName(colorFormats[fmtNdx]), "",
1093 															colorFormats[fmtNdx], IVec2(129, 117),
1094 															colorFormats[fmtNdx], IVec2(99, 128)));
1095 	}
1096 
1097 	// .texcube
1098 	{
1099 		tcu::TestCaseGroup* texCubeGroup = new tcu::TestCaseGroup(m_testCtx, "texcube", "Texture cube map tests");
1100 		addChild(texCubeGroup);
1101 
1102 		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
1103 			texCubeGroup->addChild(new FboColorTexCubeCase(m_context, getFormatName(colorFormats[fmtNdx]), "",
1104 														   colorFormats[fmtNdx], IVec2(128, 128)));
1105 	}
1106 
1107 	// .tex2darray
1108 	{
1109 		tcu::TestCaseGroup* tex2DArrayGroup = new tcu::TestCaseGroup(m_testCtx, "tex2darray", "Texture 2D array tests");
1110 		addChild(tex2DArrayGroup);
1111 
1112 		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
1113 			tex2DArrayGroup->addChild(new FboColorTex2DArrayCase(m_context, getFormatName(colorFormats[fmtNdx]), "",
1114 																 colorFormats[fmtNdx], IVec3(128, 128, 5)));
1115 	}
1116 
1117 	// .tex3d
1118 	{
1119 		tcu::TestCaseGroup* tex3DGroup = new tcu::TestCaseGroup(m_testCtx, "tex3d", "Texture 3D tests");
1120 		addChild(tex3DGroup);
1121 
1122 		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
1123 			tex3DGroup->addChild(new FboColorTex3DCase(m_context, getFormatName(colorFormats[fmtNdx]), "",
1124 													   colorFormats[fmtNdx], IVec3(128, 128, 5)));
1125 	}
1126 
1127 	// .blend
1128 	{
1129 		tcu::TestCaseGroup* blendGroup = new tcu::TestCaseGroup(m_testCtx, "blend", "Blending tests");
1130 		addChild(blendGroup);
1131 
1132 		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
1133 		{
1134 			deUint32					format		= colorFormats[fmtNdx];
1135 			tcu::TextureFormat			texFmt		= glu::mapGLInternalFormat(format);
1136 			tcu::TextureChannelClass	fmtClass	= tcu::getTextureChannelClass(texFmt.type);
1137 			string						fmtName		= getFormatName(format);
1138 
1139 			if (texFmt.type	== tcu::TextureFormat::FLOAT				||
1140 				fmtClass	== tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER	||
1141 				fmtClass	== tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
1142 				continue; // Blending is not supported.
1143 
1144 			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));
1145 		}
1146 	}
1147 
1148 	// .repeated_clear
1149 	{
1150 		tcu::TestCaseGroup* const repeatedClearGroup = new tcu::TestCaseGroup(m_testCtx, "repeated_clear", "Repeated clears and blits");
1151 		addChild(repeatedClearGroup);
1152 
1153 		// .sample.tex2d
1154 		{
1155 			tcu::TestCaseGroup* const sampleGroup = new tcu::TestCaseGroup(m_testCtx, "sample", "Read by sampling");
1156 			repeatedClearGroup->addChild(sampleGroup);
1157 
1158 			tcu::TestCaseGroup* const tex2DGroup = new tcu::TestCaseGroup(m_testCtx, "tex2d", "2D Texture");
1159 			sampleGroup->addChild(tex2DGroup);
1160 
1161 			for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
1162 				tex2DGroup->addChild(new FboRepeatedClearSampleTex2DCase(m_context, getFormatName(colorFormats[fmtNdx]),
1163 																		 "", colorFormats[fmtNdx]));
1164 		}
1165 
1166 		// .blit
1167 		{
1168 			tcu::TestCaseGroup* const blitGroup = new tcu::TestCaseGroup(m_testCtx, "blit", "Blitted");
1169 			repeatedClearGroup->addChild(blitGroup);
1170 
1171 			// .tex2d
1172 			{
1173 				tcu::TestCaseGroup* const tex2DGroup = new tcu::TestCaseGroup(m_testCtx, "tex2d", "2D Texture");
1174 				blitGroup->addChild(tex2DGroup);
1175 
1176 				for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
1177 					tex2DGroup->addChild(new FboRepeatedClearBlitTex2DCase(m_context, getFormatName(colorFormats[fmtNdx]),
1178 																		   "", colorFormats[fmtNdx]));
1179 			}
1180 
1181 			// .rbo
1182 			{
1183 				tcu::TestCaseGroup* const rboGroup = new tcu::TestCaseGroup(m_testCtx, "rbo", "Renderbuffer");
1184 				blitGroup->addChild(rboGroup);
1185 
1186 				for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
1187 					rboGroup->addChild(new FboRepeatedClearBlitRboCase(m_context, getFormatName(colorFormats[fmtNdx]),
1188 																	   "", colorFormats[fmtNdx]));
1189 			}
1190 		}
1191 	}
1192 }
1193 
1194 } // Functional
1195 } // gles3
1196 } // deqp
1197