1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 2.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Framebuffer Object Tests.
22 *
23 * Notes:
24 *   + Like in API tests, tcu::sgl2s::Context class is used.
25 *   + ReferenceContext is used to generate reference images.
26 *   + API calls can be logged \todo [pyry] Implement.
27 *//*--------------------------------------------------------------------*/
28
29#include "es2fFboRenderTest.hpp"
30#include "sglrContextUtil.hpp"
31#include "sglrGLContext.hpp"
32#include "sglrReferenceContext.hpp"
33#include "tcuSurface.hpp"
34#include "tcuTextureUtil.hpp"
35#include "tcuImageCompare.hpp"
36#include "tcuRenderTarget.hpp"
37#include "gluPixelTransfer.hpp"
38#include "gluTextureUtil.hpp"
39#include "gluStrUtil.hpp"
40#include "deRandom.hpp"
41#include "deString.h"
42
43#include "glwFunctions.hpp"
44#include "glwEnums.hpp"
45
46using std::vector;
47using std::string;
48using tcu::Vec2;
49using tcu::Vec3;
50using tcu::Vec4;
51using tcu::RGBA;
52using tcu::Surface;
53using namespace glw; // GL types
54
55namespace deqp
56{
57namespace gles2
58{
59namespace Functional
60{
61
62// Shaders.
63
64class FlatColorShader : public sglr::ShaderProgram
65{
66public:
67	FlatColorShader (void)
68		: sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
69								<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
70								<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
71								<< sglr::pdec::Uniform("u_color", glu::TYPE_FLOAT_VEC4)
72								<< sglr::pdec::VertexSource(
73										"attribute highp vec4 a_position;\n"
74										"void main (void)\n"
75										"{\n"
76										"	gl_Position = a_position;\n"
77										"}\n")
78								<< sglr::pdec::FragmentSource(
79										"uniform mediump vec4 u_color;\n"
80										"void main (void)\n"
81										"{\n"
82										"	gl_FragColor = u_color;\n"
83										"}\n"))
84	{
85	}
86
87	void setColor (sglr::Context& gl, deUint32 program, const tcu::Vec4& color)
88	{
89		gl.useProgram(program);
90		gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, color.getPtr());
91	}
92
93	void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
94	{
95		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
96			packets[packetNdx]->position = rr::readVertexAttribFloat(inputs[0], packets[packetNdx]->instanceNdx, packets[packetNdx]->vertexNdx);
97	}
98
99	void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
100	{
101		const tcu::Vec4 color(m_uniforms[0].value.f4);
102
103		DE_UNREF(packets);
104
105		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
106		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
107			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
108	}
109};
110
111class SingleTex2DShader : public sglr::ShaderProgram
112{
113public:
114	SingleTex2DShader (void)
115		: sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
116								<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
117								<< sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT)
118								<< sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
119								<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
120								<< sglr::pdec::Uniform("u_sampler0", glu::TYPE_SAMPLER_2D)
121								<< sglr::pdec::VertexSource(
122										"attribute highp vec4 a_position;\n"
123										"attribute mediump vec2 a_coord;\n"
124										"varying mediump vec2 v_coord;\n"
125										"void main (void)\n"
126										"{\n"
127										"	gl_Position = a_position;\n"
128										"	v_coord = a_coord;\n"
129										"}\n")
130								<< sglr::pdec::FragmentSource(
131										"uniform sampler2D u_sampler0;\n"
132										"varying mediump vec2 v_coord;\n"
133										"void main (void)\n"
134										"{\n"
135										"	gl_FragColor = texture2D(u_sampler0, v_coord);\n"
136										"}\n"))
137	{
138	}
139
140	void setUnit (sglr::Context& gl, deUint32 program, int unitNdx)
141	{
142		gl.useProgram(program);
143		gl.uniform1i(gl.getUniformLocation(program, "u_sampler0"), unitNdx);
144	}
145
146	void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
147	{
148		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
149		{
150			rr::VertexPacket& packet = *packets[packetNdx];
151
152			packet.position		= rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
153			packet.outputs[0]	= rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx);
154		}
155	}
156
157	void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
158	{
159		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
160		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
161		{
162			const tcu::Vec4 v_coord = rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx);
163			const float		lod		= 0.0f;
164
165			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, this->m_uniforms[0].sampler.tex2D->sample(v_coord.x(), v_coord.y(), lod));
166		}
167	}
168
169};
170
171class MixTexturesShader : public sglr::ShaderProgram
172{
173public:
174	MixTexturesShader (void)
175		: sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
176								<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
177								<< sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT)
178								<< sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
179								<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
180								<< sglr::pdec::Uniform("u_sampler0", glu::TYPE_SAMPLER_2D)
181								<< sglr::pdec::Uniform("u_sampler1", glu::TYPE_SAMPLER_2D)
182								<< sglr::pdec::VertexSource(
183										"attribute highp vec4 a_position;\n"
184										"attribute mediump vec2 a_coord;\n"
185										"varying mediump vec2 v_coord;\n"
186										"void main (void)\n"
187										"{\n"
188										"	gl_Position = a_position;\n"
189										"	v_coord = a_coord;\n"
190										"}\n")
191								<< sglr::pdec::FragmentSource(
192										"uniform sampler2D u_sampler0;\n"
193										"uniform sampler2D u_sampler1;\n"
194										"varying mediump vec2 v_coord;\n"
195										"void main (void)\n"
196										"{\n"
197										"	gl_FragColor = texture2D(u_sampler0, v_coord)*0.5 + texture2D(u_sampler1, v_coord)*0.5;\n"
198										"}\n"))
199	{
200	}
201
202	void setUnits (sglr::Context& gl, deUint32 program, int unit0, int unit1)
203	{
204		gl.useProgram(program);
205		gl.uniform1i(gl.getUniformLocation(program, "u_sampler0"), unit0);
206		gl.uniform1i(gl.getUniformLocation(program, "u_sampler1"), unit1);
207	}
208
209	void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
210	{
211		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
212		{
213			rr::VertexPacket& packet = *packets[packetNdx];
214
215			packet.position		= rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
216			packet.outputs[0]	= rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx);
217		}
218	}
219
220	void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
221	{
222		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
223		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
224		{
225			const tcu::Vec4 v_coord = rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx);
226			const float		lod		= 0.0f;
227
228			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0,   this->m_uniforms[0].sampler.tex2D->sample(v_coord.x(), v_coord.y(), lod) * 0.5f
229			                                                        + this->m_uniforms[1].sampler.tex2D->sample(v_coord.x(), v_coord.y(), lod) * 0.5f);
230		}
231	}
232};
233
234// Framebuffer config.
235
236class FboConfig
237{
238public:
239	FboConfig (void)
240		: colorbufferType		(GL_NONE)
241		, colorbufferFormat		(GL_NONE)
242		, depthbufferType		(GL_NONE)
243		, depthbufferFormat		(GL_NONE)
244		, stencilbufferType		(GL_NONE)
245		, stencilbufferFormat	(GL_NONE)
246	{
247	}
248
249	std::string				getName			(void) const;
250
251	GLenum					colorbufferType;		//!< GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP, GL_RENDERBUFFER
252	GLenum					colorbufferFormat;		//!< Internal format for color buffer texture or renderbuffer
253
254	GLenum					depthbufferType;		//!< GL_RENDERBUFFER
255	GLenum					depthbufferFormat;
256
257	GLenum					stencilbufferType;		//!< GL_RENDERBUFFER
258	GLenum					stencilbufferFormat;
259
260private:
261	static const char*		getFormatName	(GLenum format);
262};
263
264const char* FboConfig::getFormatName (GLenum format)
265{
266	switch (format)
267	{
268		case GL_RGB:				return "rgb";
269		case GL_RGBA:				return "rgba";
270		case GL_ALPHA:				return "alpha";
271		case GL_LUMINANCE:			return "luminance";
272		case GL_LUMINANCE_ALPHA:	return "luminance_alpha";
273		case GL_RGB565:				return "rgb565";
274		case GL_RGB5_A1:			return "rgb5_a1";
275		case GL_RGBA4:				return "rgba4";
276		case GL_RGBA16F:			return "rgba16f";
277		case GL_RGB16F:				return "rgb16f";
278		case GL_DEPTH_COMPONENT16:	return "depth_component16";
279		case GL_STENCIL_INDEX8:		return "stencil_index8";
280		default:					DE_ASSERT(false); return DE_NULL;
281	}
282}
283
284std::string FboConfig::getName (void) const
285{
286	std::string name = "";
287
288	if (colorbufferType != GL_NONE)
289	{
290		switch (colorbufferType)
291		{
292			case GL_TEXTURE_2D:			name += "tex2d_";	break;
293			case GL_TEXTURE_CUBE_MAP:	name += "texcube_";	break;
294			case GL_RENDERBUFFER:		name += "rbo_";		break;
295			default:					DE_ASSERT(false);	break;
296		}
297		name += getFormatName(colorbufferFormat);
298	}
299
300	if (depthbufferType != GL_NONE)
301	{
302		DE_ASSERT(depthbufferType == GL_RENDERBUFFER);
303		if (name.length() > 0)
304			name += "_";
305		name += getFormatName(depthbufferFormat);
306	}
307
308	if (stencilbufferType != GL_NONE)
309	{
310		DE_ASSERT(stencilbufferType == GL_RENDERBUFFER);
311		if (name.length() > 0)
312			name += "_";
313		name += getFormatName(stencilbufferFormat);
314	}
315
316	return name;
317}
318
319class FboIncompleteException : public tcu::TestError
320{
321public:
322						FboIncompleteException		(const FboConfig& config, GLenum reason, const char* file, int line);
323	virtual				~FboIncompleteException		(void) throw() {}
324
325	const FboConfig&	getConfig					(void) const { return m_config; }
326	GLenum				getReason					(void) const { return m_reason; }
327
328private:
329	FboConfig			m_config;
330	GLenum				m_reason;
331};
332
333static const char* getFboIncompleteReasonName (GLenum reason)
334{
335	switch (reason)
336	{
337		case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:			return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
338		case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:	return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
339		case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:			return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
340		case GL_FRAMEBUFFER_UNSUPPORTED:					return "GL_FRAMEBUFFER_UNSUPPORTED";
341		case GL_FRAMEBUFFER_COMPLETE:						return "GL_FRAMEBUFFER_COMPLETE";
342		default:											return "UNKNOWN";
343	}
344}
345
346FboIncompleteException::FboIncompleteException (const FboConfig& config, GLenum reason, const char* file, int line)
347	: TestError("Framebuffer is not complete", getFboIncompleteReasonName(reason), file, line)
348	, m_config(config)
349	, m_reason(reason)
350{
351}
352
353class Framebuffer
354{
355public:
356						Framebuffer			(sglr::Context& context, const FboConfig& config, int width, int height, deUint32 fbo = 0, deUint32 colorbuffer = 0, deUint32 depthbuffer = 0, deUint32 stencilbuffer = 0);
357						~Framebuffer		(void);
358
359	const FboConfig&	getConfig			(void) const { return m_config; }
360	deUint32			getFramebuffer		(void) const { return m_framebuffer; }
361	deUint32			getColorbuffer		(void) const { return m_colorbuffer; }
362	deUint32			getDepthbuffer		(void) const { return m_depthbuffer; }
363	deUint32			getStencilbuffer	(void) const { return m_stencilbuffer; }
364
365	void				checkCompleteness	(void);
366
367private:
368	void				createRbo			(deUint32& name, GLenum format, int width, int height);
369	void				destroyBuffer		(deUint32 name, GLenum type);
370
371	FboConfig			m_config;
372	sglr::Context&		m_context;
373	deUint32			m_framebuffer;
374	deUint32			m_colorbuffer;
375	deUint32			m_depthbuffer;
376	deUint32			m_stencilbuffer;
377};
378
379static bool isExtensionSupported (sglr::Context& context, const char* name)
380{
381	std::istringstream extensions(context.getString(GL_EXTENSIONS));
382	std::string extension;
383
384	while (std::getline(extensions, extension, ' '))
385	{
386		if (extension == name)
387			return true;
388	}
389
390	return false;
391}
392
393static void checkColorFormatSupport (sglr::Context& context, deUint32 sizedFormat)
394{
395	switch (sizedFormat)
396	{
397		case GL_RGBA16F:
398		case GL_RGB16F:
399		case GL_RG16F:
400		case GL_R16F:
401			if (!isExtensionSupported(context, "GL_EXT_color_buffer_half_float"))
402				throw tcu::NotSupportedError("GL_EXT_color_buffer_half_float is not supported");
403
404		default:
405			break;
406	}
407}
408
409Framebuffer::Framebuffer (sglr::Context& context, const FboConfig& config, int width, int height, deUint32 fbo, deUint32 colorbuffer, deUint32 depthbuffer, deUint32 stencilbuffer)
410	: m_config			(config)
411	, m_context			(context)
412	, m_framebuffer		(fbo)
413	, m_colorbuffer		(colorbuffer)
414	, m_depthbuffer		(depthbuffer)
415	, m_stencilbuffer	(stencilbuffer)
416{
417	// Verify that color format is supported
418	checkColorFormatSupport(context, config.colorbufferFormat);
419
420	if (m_framebuffer == 0)
421		context.genFramebuffers(1, &m_framebuffer);
422	context.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
423
424	switch (m_config.colorbufferType)
425	{
426		case GL_TEXTURE_2D:
427			if (m_colorbuffer == 0)
428				context.genTextures(1, &m_colorbuffer);
429			context.bindTexture(GL_TEXTURE_2D, m_colorbuffer);
430			context.texImage2D(GL_TEXTURE_2D, 0, m_config.colorbufferFormat, width, height);
431			context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
432
433			if (!deIsPowerOfTwo32(width) || !deIsPowerOfTwo32(height))
434			{
435				// Set wrap mode to clamp for NPOT FBOs
436				context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
437				context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
438			}
439
440			context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorbuffer, 0);
441			break;
442
443		case GL_TEXTURE_CUBE_MAP:
444			DE_FATAL("TODO");
445			break;
446
447		case GL_RENDERBUFFER:
448			createRbo(m_colorbuffer, m_config.colorbufferFormat, width, height);
449			context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorbuffer);
450			break;
451
452		default:
453			DE_ASSERT(m_config.colorbufferType == GL_NONE);
454			break;
455	}
456
457	if (m_config.depthbufferType == GL_RENDERBUFFER)
458	{
459		createRbo(m_depthbuffer, m_config.depthbufferFormat, width, height);
460		context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthbuffer);
461	}
462	else
463		DE_ASSERT(m_config.depthbufferType == GL_NONE);
464
465	if (m_config.stencilbufferType == GL_RENDERBUFFER)
466	{
467		createRbo(m_stencilbuffer, m_config.stencilbufferFormat, width, height);
468		context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_stencilbuffer);
469	}
470	else
471		DE_ASSERT(m_config.stencilbufferType == GL_NONE);
472
473	context.bindFramebuffer(GL_FRAMEBUFFER, 0);
474}
475
476Framebuffer::~Framebuffer (void)
477{
478	m_context.deleteFramebuffers(1, &m_framebuffer);
479	destroyBuffer(m_colorbuffer, m_config.colorbufferType);
480	destroyBuffer(m_depthbuffer, m_config.depthbufferType);
481	destroyBuffer(m_stencilbuffer, m_config.stencilbufferType);
482}
483
484void Framebuffer::checkCompleteness (void)
485{
486	m_context.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
487	GLenum status = m_context.checkFramebufferStatus(GL_FRAMEBUFFER);
488	m_context.bindFramebuffer(GL_FRAMEBUFFER, 0);
489	if (status != GL_FRAMEBUFFER_COMPLETE)
490		throw FboIncompleteException(m_config, status, __FILE__, __LINE__);
491}
492
493void Framebuffer::createRbo (deUint32& name, GLenum format, int width, int height)
494{
495	if (name == 0)
496		m_context.genRenderbuffers(1, &name);
497	m_context.bindRenderbuffer(GL_RENDERBUFFER, name);
498	m_context.renderbufferStorage(GL_RENDERBUFFER, format, width, height);
499}
500
501void Framebuffer::destroyBuffer (deUint32 name, GLenum type)
502{
503	if (type == GL_TEXTURE_2D || type == GL_TEXTURE_CUBE_MAP)
504		m_context.deleteTextures(1, &name);
505	else if (type == GL_RENDERBUFFER)
506		m_context.deleteRenderbuffers(1, &name);
507	else
508		DE_ASSERT(type == GL_NONE);
509}
510
511static void createMetaballsTex2D (sglr::Context& context, deUint32 name, GLenum format, GLenum dataType, int width, int height)
512{
513	tcu::TextureFormat	texFormat	= glu::mapGLTransferFormat(format, dataType);
514	tcu::TextureLevel	level		(texFormat, width, height);
515
516	tcu::fillWithMetaballs(level.getAccess(), 5, name ^ width ^ height);
517
518	context.bindTexture(GL_TEXTURE_2D, name);
519	context.texImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, dataType, level.getAccess().getDataPtr());
520	context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
521}
522
523static void createQuadsTex2D (sglr::Context& context, deUint32 name, GLenum format, GLenum dataType, int width, int height)
524{
525	tcu::TextureFormat	texFormat	= glu::mapGLTransferFormat(format, dataType);
526	tcu::TextureLevel	level		(texFormat, width, height);
527
528	tcu::fillWithRGBAQuads(level.getAccess());
529
530	context.bindTexture(GL_TEXTURE_2D, name);
531	context.texImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, dataType, level.getAccess().getDataPtr());
532	context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
533}
534
535class FboRenderCase : public TestCase
536{
537public:
538								FboRenderCase			(Context& context, const char* name, const char* description, const FboConfig& config);
539	virtual						~FboRenderCase			(void) {}
540
541	virtual IterateResult		iterate					(void);
542	virtual void				render					(sglr::Context& fboContext, Surface& dst) = DE_NULL;
543
544	const FboConfig&			getConfig				(void) const { return m_config; }
545
546	static bool					isConfigSupported		(const FboConfig& config) { DE_UNREF(config); return true; }
547
548private:
549	FboConfig					m_config;
550};
551
552FboRenderCase::FboRenderCase (Context& context, const char* name, const char* description, const FboConfig& config)
553	: TestCase(context, name, description)
554	, m_config(config)
555{
556}
557
558TestCase::IterateResult FboRenderCase::iterate (void)
559{
560	Vec4						clearColor				(0.125f, 0.25f, 0.5f, 1.0f);
561	glu::RenderContext&			renderCtx				= m_context.getRenderContext();
562	const tcu::RenderTarget&	renderTarget			= m_context.getRenderTarget();
563	tcu::TestLog&				log						= m_testCtx.getLog();
564	const char*					failReason				= DE_NULL;
565
566	// Position & size for context
567	deRandom rnd;
568	deRandom_init(&rnd, deStringHash(getName()));
569
570	int		width	= deMin32(renderTarget.getWidth(), 128);
571	int		height	= deMin32(renderTarget.getHeight(), 128);
572	int		xMax	= renderTarget.getWidth()-width+1;
573	int		yMax	= renderTarget.getHeight()-height+1;
574	int		x		= deRandom_getUint32(&rnd) % xMax;
575	int		y		= deRandom_getUint32(&rnd) % yMax;
576
577	tcu::Surface	gles2Frame	(width, height);
578	tcu::Surface	refFrame	(width, height);
579	GLenum			gles2Error;
580	GLenum			refError;
581
582	// Render using GLES2
583	try
584	{
585		sglr::GLContext context(renderCtx, log, sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(x, y, width, height));
586
587		context.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
588		context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
589
590		render(context, gles2Frame); // Call actual render func
591		gles2Error = context.getError();
592	}
593	catch (const FboIncompleteException& e)
594	{
595		if (e.getReason() == GL_FRAMEBUFFER_UNSUPPORTED)
596		{
597			// Mark test case as unsupported
598			log << e;
599			m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported");
600			return STOP;
601		}
602		else
603			throw; // Propagate error
604	}
605
606	// Render reference image
607	{
608		sglr::ReferenceContextBuffers	buffers	(tcu::PixelFormat(8,8,8,renderTarget.getPixelFormat().alphaBits?8:0), renderTarget.getDepthBits(), renderTarget.getStencilBits(), width, height);
609		sglr::ReferenceContext			context	(sglr::ReferenceContextLimits(renderCtx), buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer());
610
611		context.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
612		context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
613
614		render(context, refFrame);
615		refError = context.getError();
616	}
617
618	// Compare error codes
619	bool errorCodesOk = (gles2Error == refError);
620
621	if (!errorCodesOk)
622	{
623		log << tcu::TestLog::Message << "Error code mismatch: got " << glu::getErrorStr(gles2Error) << ", expected " << glu::getErrorStr(refError) << tcu::TestLog::EndMessage;
624		failReason = "Got unexpected error";
625	}
626
627	// Compare images
628	const float		threshold	= 0.05f;
629	bool			imagesOk	= tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refFrame, gles2Frame, threshold, tcu::COMPARE_LOG_RESULT);
630
631	if (!imagesOk && !failReason)
632		failReason = "Image comparison failed";
633
634	// Store test result
635	bool isOk = errorCodesOk && imagesOk;
636	m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
637							isOk ? "Pass"				: failReason);
638
639	return STOP;
640}
641
642namespace FboCases
643{
644
645class ColorClearsTest : public FboRenderCase
646{
647public:
648						ColorClearsTest				(Context& context, const FboConfig& config);
649						~ColorClearsTest			(void) {}
650
651	void				render						(sglr::Context& context, Surface& dst);
652};
653
654ColorClearsTest::ColorClearsTest (Context& context, const FboConfig& config)
655	: FboRenderCase(context, config.getName().c_str(), "Color buffer clears", config)
656{
657}
658
659void ColorClearsTest::render (sglr::Context& context, Surface& dst)
660{
661	int			width	= 128;
662	int			height	= 128;
663	deRandom	rnd;
664
665	deRandom_init(&rnd, 0);
666
667	// Create framebuffer
668	Framebuffer fbo(context, getConfig(), width, height);
669	fbo.checkCompleteness();
670
671	// Clear fbo
672	context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
673	context.viewport(0, 0, width, height);
674	context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
675	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
676
677	// Enable scissor test.
678	context.enable(GL_SCISSOR_TEST);
679
680	// Do 10 random color clears
681	for (int i = 0; i < 15; i++)
682	{
683		int		cX		= (int)(deRandom_getUint32(&rnd) & 0x7fffffff) % width;
684		int		cY		= (int)(deRandom_getUint32(&rnd) & 0x7fffffff) % height;
685		int		cWidth	= (int)(deRandom_getUint32(&rnd) & 0x7fffffff) % (width-cX);
686		int		cHeight	= (int)(deRandom_getUint32(&rnd) & 0x7fffffff) % (height-cY);
687		Vec4	color	= RGBA(deRandom_getUint32(&rnd)).toVec();
688
689		context.scissor(cX, cY, cWidth, cHeight);
690		context.clearColor(color.x(), color.y(), color.z(), color.w());
691		context.clear(GL_COLOR_BUFFER_BIT);
692	}
693
694	// Disable scissor.
695	context.disable(GL_SCISSOR_TEST);
696
697	if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D)
698	{
699		// Unbind fbo
700		context.bindFramebuffer(GL_FRAMEBUFFER, 0);
701
702		// Draw to screen
703		SingleTex2DShader	shader;
704		deUint32			shaderID = context.createProgram(&shader);
705
706		shader.setUnit(context, shaderID, 0);
707
708		context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
709		context.viewport(0, 0, context.getWidth(), context.getHeight());
710		sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
711
712		// Read from screen
713		context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
714	}
715	else
716	{
717		// clear alpha channel for GL_RGB5_A1 format because test
718		// thresholds for the alpha channel do not account for dithering
719		if(getConfig().colorbufferFormat == GL_RGB5_A1)
720		{
721			context.colorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
722			context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
723			context.clear(GL_COLOR_BUFFER_BIT);
724			context.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
725		}
726
727		// Read from fbo
728		context.readPixels(dst, 0, 0, width, height);
729	}
730}
731
732class IntersectingQuadsTest : public FboRenderCase
733{
734public:
735					IntersectingQuadsTest			(Context& context, const FboConfig& config, bool npot = false);
736	virtual			~IntersectingQuadsTest			(void) {}
737
738	virtual void	render							(sglr::Context& context, Surface& dst);
739
740	static bool		isConfigSupported				(const FboConfig& config);
741
742private:
743	int				m_fboWidth;
744	int				m_fboHeight;
745};
746
747class IntersectingQuadsNpotTest : public IntersectingQuadsTest
748{
749public:
750	IntersectingQuadsNpotTest (Context& context, const FboConfig& config)
751		: IntersectingQuadsTest(context, config, true)
752	{
753	}
754};
755
756IntersectingQuadsTest::IntersectingQuadsTest (Context& context, const FboConfig& config, bool npot)
757	: FboRenderCase	(context, (string(npot ? "npot_" : "") + config.getName()).c_str(), "Intersecting textured quads", config)
758	, m_fboWidth	(npot ? 127 : 128)
759	, m_fboHeight	(npot ?  95 : 128)
760{
761}
762
763bool IntersectingQuadsTest::isConfigSupported (const FboConfig& config)
764{
765	// \note Disabled for stencil configurations since doesn't exercise stencil buffer
766	return config.depthbufferType	!= GL_NONE &&
767		   config.stencilbufferType	== GL_NONE;
768}
769
770void IntersectingQuadsTest::render (sglr::Context& ctx, Surface& dst)
771{
772	SingleTex2DShader	texShader;
773	deUint32			texShaderID = ctx.createProgram(&texShader);
774
775	deUint32 metaballsTex	= 1;
776	deUint32 quadsTex		= 2;
777
778	createMetaballsTex2D(ctx, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
779	createQuadsTex2D(ctx, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
780
781	int width	= m_fboWidth;
782	int height	= m_fboHeight;
783	Framebuffer fbo(ctx, getConfig(), width, height);
784	fbo.checkCompleteness();
785
786	// Setup shaders
787	texShader.setUnit(ctx, texShaderID, 0);
788
789	// Draw scene
790	ctx.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
791	ctx.viewport(0, 0, width, height);
792	ctx.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
793	ctx.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
794
795	ctx.enable(GL_DEPTH_TEST);
796
797	ctx.bindTexture(GL_TEXTURE_2D, metaballsTex);
798	sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f));
799
800	ctx.bindTexture(GL_TEXTURE_2D, quadsTex);
801	sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 1.0f), Vec3(1.0f, 1.0f, -1.0f));
802
803	ctx.disable(GL_DEPTH_TEST);
804
805	if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D)
806	{
807		// Unbind fbo
808		ctx.bindFramebuffer(GL_FRAMEBUFFER, 0);
809
810		// Draw to screen
811		ctx.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
812		ctx.viewport(0, 0, ctx.getWidth(), ctx.getHeight());
813		sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
814
815		// Read from screen
816		ctx.readPixels(dst, 0, 0, ctx.getWidth(), ctx.getHeight());
817	}
818	else
819	{
820		// Read from fbo
821		ctx.readPixels(dst, 0, 0, width, height);
822	}
823}
824
825class MixTest : public FboRenderCase
826{
827public:
828						MixTest				(Context& context, const FboConfig& config, bool npot = false);
829	virtual				~MixTest			(void) {}
830
831	void				render				(sglr::Context& context, Surface& dst);
832
833	static bool			isConfigSupported	(const FboConfig& config);
834
835private:
836	int					m_fboAWidth;
837	int					m_fboAHeight;
838	int					m_fboBWidth;
839	int					m_fboBHeight;
840};
841
842class MixNpotTest : public MixTest
843{
844public:
845	MixNpotTest (Context& context, const FboConfig& config)
846		: MixTest(context, config, true)
847	{
848	}
849};
850
851MixTest::MixTest (Context& context, const FboConfig& config, bool npot)
852	: FboRenderCase	(context, (string(npot ? "mix_npot_" : "mix_") + config.getName()).c_str(), "Use two fbos as sources in draw operation", config)
853	, m_fboAWidth	(npot ? 127 : 128)
854	, m_fboAHeight	(npot ?  95 : 128)
855	, m_fboBWidth	(npot ?  55 :  64)
856	, m_fboBHeight	(npot ?  63 :  64)
857{
858}
859
860bool MixTest::isConfigSupported (const FboConfig& config)
861{
862	// \note Disabled for stencil configurations since doesn't exercise stencil buffer
863	return config.colorbufferType	== GL_TEXTURE_2D &&
864		   config.stencilbufferType	== GL_NONE;
865}
866
867void MixTest::render (sglr::Context& context, Surface& dst)
868{
869	SingleTex2DShader	singleTexShader;
870	MixTexturesShader	mixShader;
871
872	deUint32			singleTexShaderID	= context.createProgram(&singleTexShader);
873	deUint32			mixShaderID			= context.createProgram(&mixShader);
874
875	// Texture with metaballs
876	deUint32 metaballsTex = 1;
877	context.pixelStorei(GL_UNPACK_ALIGNMENT, 1);
878	createMetaballsTex2D(context, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
879
880	// Setup shaders
881	singleTexShader.setUnit(context, singleTexShaderID, 0);
882	mixShader.setUnits(context, mixShaderID, 0, 1);
883
884	// Fbo, quad with metaballs texture
885	Framebuffer fboA(context, getConfig(), m_fboAWidth, m_fboAHeight);
886	fboA.checkCompleteness();
887	context.bindFramebuffer(GL_FRAMEBUFFER, fboA.getFramebuffer());
888	context.viewport(0, 0, m_fboAWidth, m_fboAHeight);
889	context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
890	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
891	context.bindTexture(GL_TEXTURE_2D, metaballsTex);
892	sglr::drawQuad(context, singleTexShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
893
894	// Fbo, color clears
895	Framebuffer fboB(context, getConfig(), m_fboBWidth, m_fboBHeight);
896	fboB.checkCompleteness();
897	context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer());
898	context.viewport(0, 0, m_fboBWidth, m_fboBHeight);
899	context.enable(GL_SCISSOR_TEST);
900	context.scissor(0, 0, 32, 64);
901	context.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
902	context.clear(GL_COLOR_BUFFER_BIT);
903	context.scissor(32, 0, 32, 64);
904	context.clearColor(0.0f, 1.0f, 0.0f, 1.0f);
905	context.clear(GL_COLOR_BUFFER_BIT);
906	context.disable(GL_SCISSOR_TEST);
907
908	// Final mix op
909	context.activeTexture(GL_TEXTURE0);
910	context.bindTexture(GL_TEXTURE_2D, fboA.getColorbuffer());
911	context.activeTexture(GL_TEXTURE1);
912	context.bindTexture(GL_TEXTURE_2D, fboB.getColorbuffer());
913	context.bindFramebuffer(GL_FRAMEBUFFER, 0);
914	context.viewport(0, 0, context.getWidth(), context.getHeight());
915	sglr::drawQuad(context, mixShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
916
917	context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
918}
919
920class BlendTest : public FboRenderCase
921{
922public:
923						BlendTest			(Context& context, const FboConfig& config, bool npot = false);
924	virtual				~BlendTest			(void) {}
925
926	void				render				(sglr::Context& context, Surface& dst);
927
928	static bool			isConfigSupported	(const FboConfig& config);
929
930private:
931	int					m_fboWidth;
932	int					m_fboHeight;
933};
934
935class BlendNpotTest : public BlendTest
936{
937public:
938	BlendNpotTest (Context& context, const FboConfig& config)
939		: BlendTest(context, config, true)
940	{
941	}
942};
943
944BlendTest::BlendTest (Context& context, const FboConfig& config, bool npot)
945	: FboRenderCase	(context, (string(npot ? "blend_npot_" : "blend_") + config.getName()).c_str(), "Blend to fbo", config)
946	, m_fboWidth	(npot ? 111 : 128)
947	, m_fboHeight	(npot ? 122 : 128)
948{
949}
950
951bool BlendTest::isConfigSupported (const FboConfig& config)
952{
953	// \note Disabled for stencil configurations since doesn't exercise stencil buffer
954	return config.stencilbufferType	== GL_NONE;
955}
956
957void BlendTest::render (sglr::Context& context, Surface& dst)
958{
959	SingleTex2DShader	shader;
960	deUint32			shaderID		= context.createProgram(&shader);
961	int					width			= m_fboWidth;
962	int					height			= m_fboHeight;
963	deUint32			metaballsTex	= 1;
964
965	createMetaballsTex2D(context, metaballsTex, GL_RGBA, GL_UNSIGNED_BYTE, 64, 64);
966
967	Framebuffer fbo(context, getConfig(), width, height);
968	fbo.checkCompleteness();
969
970	shader.setUnit(context, shaderID, 0);
971
972	context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
973	context.viewport(0, 0, width, height);
974	context.bindTexture(GL_TEXTURE_2D, metaballsTex);
975	context.clearColor(0.6f, 0.0f, 0.6f, 1.0f);
976	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
977
978	context.enable(GL_BLEND);
979	context.blendEquation(GL_FUNC_ADD);
980	context.blendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
981	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
982	context.disable(GL_BLEND);
983
984	if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D)
985	{
986		context.bindFramebuffer(GL_FRAMEBUFFER, 0);
987		context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
988		context.viewport(0, 0, context.getWidth(), context.getHeight());
989		sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
990		context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
991	}
992	else
993		context.readPixels(dst, 0, 0, width, height);
994}
995
996class StencilClearsTest : public FboRenderCase
997{
998public:
999						StencilClearsTest		(Context& context, const FboConfig& config);
1000	virtual				~StencilClearsTest		(void) {}
1001
1002	void				render					(sglr::Context& context, Surface& dst);
1003
1004	static bool			isConfigSupported		(const FboConfig& config);
1005};
1006
1007StencilClearsTest::StencilClearsTest (Context& context, const FboConfig& config)
1008	: FboRenderCase(context, config.getName().c_str(), "Stencil clears", config)
1009{
1010}
1011
1012void StencilClearsTest::render (sglr::Context& context, Surface& dst)
1013{
1014	SingleTex2DShader	shader;
1015	deUint32			shaderID		= context.createProgram(&shader);
1016	int					width			= 128;
1017	int					height			= 128;
1018	deUint32			quadsTex		= 1;
1019	deUint32			metaballsTex	= 2;
1020
1021	createQuadsTex2D(context, quadsTex, GL_RGBA, GL_UNSIGNED_BYTE, width, height);
1022	createMetaballsTex2D(context, metaballsTex, GL_RGBA, GL_UNSIGNED_BYTE, width, height);
1023
1024	Framebuffer fbo(context, getConfig(), width, height);
1025	fbo.checkCompleteness();
1026
1027	// Bind framebuffer and clear
1028	context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1029	context.viewport(0, 0, width, height);
1030	context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1031	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1032
1033	// Do stencil clears
1034	context.enable(GL_SCISSOR_TEST);
1035	context.scissor(10, 16, 32, 120);
1036	context.clearStencil(1);
1037	context.clear(GL_STENCIL_BUFFER_BIT);
1038	context.scissor(16, 32, 100, 64);
1039	context.clearStencil(2);
1040	context.clear(GL_STENCIL_BUFFER_BIT);
1041	context.disable(GL_SCISSOR_TEST);
1042
1043	// Draw 2 textures with stecil tests
1044	context.activeTexture(GL_TEXTURE0);
1045	context.bindTexture(GL_TEXTURE_2D, quadsTex);
1046	context.activeTexture(GL_TEXTURE1);
1047	context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1048
1049	context.enable(GL_STENCIL_TEST);
1050	context.stencilFunc(GL_EQUAL, 1, 0xffffffffu);
1051	shader.setUnit(context, shaderID, 0);
1052	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1053
1054	context.stencilFunc(GL_EQUAL, 2, 0xffffffffu);
1055	shader.setUnit(context, shaderID, 1);
1056	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1057
1058	context.disable(GL_STENCIL_TEST);
1059
1060	if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D)
1061	{
1062		context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1063		context.activeTexture(GL_TEXTURE0);
1064		context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
1065		context.viewport(0, 0, context.getWidth(), context.getHeight());
1066		shader.setUnit(context, shaderID, 0);
1067		sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1068		context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1069	}
1070	else
1071	{
1072		// clear alpha channel for GL_RGB5_A1 format because test
1073		// thresholds for the alpha channel do not account for dithering
1074		if(getConfig().colorbufferFormat == GL_RGB5_A1)
1075		{
1076			context.colorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
1077			context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1078			context.clear(GL_COLOR_BUFFER_BIT);
1079			context.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1080		}
1081
1082		context.readPixels(dst, 0, 0, width, height);
1083	}
1084}
1085
1086bool StencilClearsTest::isConfigSupported (const FboConfig& config)
1087{
1088	return config.stencilbufferType != GL_NONE;
1089}
1090
1091class StencilTest : public FboRenderCase
1092{
1093public:
1094						StencilTest				(Context& context, const FboConfig& config, bool npot = false);
1095	virtual				~StencilTest			(void) {}
1096
1097	void				render					(sglr::Context& context, Surface& dst);
1098
1099	static bool			isConfigSupported		(const FboConfig& config);
1100
1101private:
1102	int					m_fboWidth;
1103	int					m_fboHeight;
1104};
1105
1106class StencilNpotTest : public StencilTest
1107{
1108public:
1109	StencilNpotTest (Context& context, const FboConfig& config)
1110		: StencilTest(context, config, true)
1111	{
1112	}
1113};
1114
1115StencilTest::StencilTest (Context& context, const FboConfig& config, bool npot)
1116	: FboRenderCase	(context, (string(npot ? "npot_" : "") + config.getName()).c_str(), "Stencil ops", config)
1117	, m_fboWidth	(npot ?  99 : 128)
1118	, m_fboHeight	(npot ? 110 : 128)
1119{
1120}
1121
1122bool StencilTest::isConfigSupported (const FboConfig& config)
1123{
1124	return config.stencilbufferType != GL_NONE;
1125}
1126
1127void StencilTest::render (sglr::Context& ctx, Surface& dst)
1128{
1129	FlatColorShader		colorShader;
1130	SingleTex2DShader	texShader;
1131	deUint32			colorShaderID	= ctx.createProgram(&colorShader);
1132	deUint32			texShaderID		= ctx.createProgram(&texShader);
1133	int					width			= m_fboWidth;
1134	int					height			= m_fboHeight;
1135	int					texWidth		= 64;
1136	int					texHeight		= 64;
1137	deUint32			quadsTex		= 1;
1138	deUint32			metaballsTex	= 2;
1139	bool				depth			= getConfig().depthbufferType != GL_NONE;
1140
1141	createQuadsTex2D(ctx, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight);
1142	createMetaballsTex2D(ctx, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight);
1143
1144	Framebuffer fbo(ctx, getConfig(), width, height);
1145	fbo.checkCompleteness();
1146
1147	// Bind framebuffer and clear
1148	ctx.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1149	ctx.viewport(0, 0, width, height);
1150	ctx.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1151	ctx.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1152
1153	// Render intersecting quads - increment stencil on depth pass
1154	ctx.enable(GL_DEPTH_TEST);
1155	ctx.enable(GL_STENCIL_TEST);
1156	ctx.stencilFunc(GL_ALWAYS, 0, 0xffu);
1157	ctx.stencilOp(GL_KEEP, GL_KEEP, GL_INCR);
1158
1159	colorShader.setColor(ctx, colorShaderID, Vec4(0.0f, 0.0f, 1.0f, 1.0f));
1160	sglr::drawQuad(ctx, colorShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
1161
1162	ctx.bindTexture(GL_TEXTURE_2D, quadsTex);
1163	texShader.setUnit(ctx, texShaderID, 0);
1164	sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(+1.0f, +1.0f, +1.0f));
1165
1166	// Draw quad with stencil test (stencil == 1 or 2 depending on depth) - decrement on stencil failure
1167	ctx.disable(GL_DEPTH_TEST);
1168	ctx.stencilFunc(GL_EQUAL, depth ? 2 : 1, 0xffu);
1169	ctx.stencilOp(GL_DECR, GL_KEEP, GL_KEEP);
1170	colorShader.setColor(ctx, colorShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1171	sglr::drawQuad(ctx, colorShaderID, Vec3(-0.5f, -0.5f, 0.0f), Vec3(+0.5f, +0.5f, 0.0f));
1172
1173	// Draw metaballs with stencil test where stencil > 1 or 2 depending on depth buffer
1174	ctx.bindTexture(GL_TEXTURE_2D, metaballsTex);
1175	ctx.stencilFunc(GL_GREATER, depth ? 1 : 2, 0xffu);
1176	ctx.stencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1177	sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
1178
1179	ctx.disable(GL_STENCIL_TEST);
1180
1181	if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D)
1182	{
1183		ctx.bindFramebuffer(GL_FRAMEBUFFER, 0);
1184		ctx.activeTexture(GL_TEXTURE0);
1185		ctx.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
1186		ctx.viewport(0, 0, ctx.getWidth(), ctx.getHeight());
1187		sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1188		ctx.readPixels(dst, 0, 0, ctx.getWidth(), ctx.getHeight());
1189	}
1190	else
1191		ctx.readPixels(dst, 0, 0, width, height);
1192}
1193
1194class SharedColorbufferTest : public FboRenderCase
1195{
1196public:
1197						SharedColorbufferTest			(Context& context, const FboConfig& config);
1198	virtual				~SharedColorbufferTest			(void) {}
1199
1200	void				render							(sglr::Context& context, Surface& dst);
1201};
1202
1203SharedColorbufferTest::SharedColorbufferTest (Context& context, const FboConfig& config)
1204	: FboRenderCase(context, config.getName().c_str(), "Shared colorbuffer", config)
1205{
1206}
1207
1208void SharedColorbufferTest::render (sglr::Context& context, Surface& dst)
1209{
1210	SingleTex2DShader	shader;
1211	deUint32			shaderID		= context.createProgram(&shader);
1212	int					width			= 128;
1213	int					height			= 128;
1214//	bool				depth			= getConfig().depthbufferFormat		!= GL_NONE;
1215	bool				stencil			= getConfig().stencilbufferFormat	!= GL_NONE;
1216
1217	// Textures
1218	deUint32	quadsTex		= 1;
1219	deUint32	metaballsTex	= 2;
1220	createQuadsTex2D(context, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1221	createMetaballsTex2D(context, metaballsTex, GL_RGBA, GL_UNSIGNED_BYTE, 64, 64);
1222
1223	context.viewport(0, 0, width, height);
1224
1225	shader.setUnit(context, shaderID, 0);
1226
1227	// Fbo A
1228	Framebuffer fboA(context, getConfig(), width, height);
1229	fboA.checkCompleteness();
1230
1231	// Fbo B - don't create colorbuffer
1232	FboConfig cfg = getConfig();
1233	cfg.colorbufferType		= GL_NONE;
1234	cfg.colorbufferFormat	= GL_NONE;
1235	Framebuffer fboB(context, cfg, width, height);
1236
1237	// Attach color buffer from fbo A
1238	context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer());
1239	switch (getConfig().colorbufferType)
1240	{
1241		case GL_TEXTURE_2D:
1242			context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboA.getColorbuffer(), 0);
1243			break;
1244
1245		case GL_RENDERBUFFER:
1246			context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fboA.getColorbuffer());
1247			break;
1248
1249		default:
1250			DE_ASSERT(false);
1251	}
1252
1253	// Clear depth and stencil in fbo B
1254	context.clear(GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1255
1256	// Render quads to fbo 1, with depth 0.0
1257	context.bindFramebuffer(GL_FRAMEBUFFER, fboA.getFramebuffer());
1258	context.bindTexture(GL_TEXTURE_2D, quadsTex);
1259	context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1260	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1261
1262	if (stencil)
1263	{
1264		// Stencil to 1 in fbo A
1265		context.clearStencil(1);
1266		context.clear(GL_STENCIL_BUFFER_BIT);
1267	}
1268
1269	context.enable(GL_DEPTH_TEST);
1270	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1271	context.disable(GL_DEPTH_TEST);
1272
1273	// Blend metaballs to fbo 2
1274	context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer());
1275	context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1276	context.enable(GL_BLEND);
1277	context.blendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
1278	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1279
1280	// Render small quad that is only visible if depth buffer is not shared with fbo A - or there is no depth bits
1281	context.bindTexture(GL_TEXTURE_2D, quadsTex);
1282	context.enable(GL_DEPTH_TEST);
1283	sglr::drawQuad(context, shaderID, Vec3(0.5f, 0.5f, 0.5f), Vec3(1.0f, 1.0f, 0.5f));
1284	context.disable(GL_DEPTH_TEST);
1285
1286	if (stencil)
1287	{
1288		FlatColorShader flatShader;
1289		deUint32		flatShaderID = context.createProgram(&flatShader);
1290
1291		flatShader.setColor(context, flatShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1292
1293		// Clear subset of stencil buffer to 1
1294		context.enable(GL_SCISSOR_TEST);
1295		context.scissor(10, 10, 12, 25);
1296		context.clearStencil(1);
1297		context.clear(GL_STENCIL_BUFFER_BIT);
1298		context.disable(GL_SCISSOR_TEST);
1299
1300		// Render quad with stencil mask == 1
1301		context.enable(GL_STENCIL_TEST);
1302		context.stencilFunc(GL_EQUAL, 1, 0xffu);
1303		sglr::drawQuad(context, flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1304		context.disable(GL_STENCIL_TEST);
1305	}
1306
1307	// Get results
1308	if (fboA.getConfig().colorbufferType == GL_TEXTURE_2D)
1309	{
1310		context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1311		context.bindTexture(GL_TEXTURE_2D, fboA.getColorbuffer());
1312		context.viewport(0, 0, context.getWidth(), context.getHeight());
1313		sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1314		context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1315	}
1316	else
1317		context.readPixels(dst, 0, 0, width, height);
1318}
1319
1320class SharedColorbufferClearsTest : public FboRenderCase
1321{
1322public:
1323					SharedColorbufferClearsTest		(Context& context, const FboConfig& config);
1324	virtual			~SharedColorbufferClearsTest	(void) {}
1325
1326	static bool		isConfigSupported				(const FboConfig& config);
1327	void			render							(sglr::Context& context, Surface& dst);
1328};
1329
1330SharedColorbufferClearsTest::SharedColorbufferClearsTest (Context& context, const FboConfig& config)
1331	: FboRenderCase(context, config.getName().c_str(), "Shared colorbuffer clears", config)
1332{
1333}
1334
1335bool SharedColorbufferClearsTest::isConfigSupported (const FboConfig& config)
1336{
1337	return config.colorbufferType	!= GL_NONE &&
1338		   config.depthbufferType	== GL_NONE &&
1339		   config.stencilbufferType	== GL_NONE;
1340}
1341
1342void SharedColorbufferClearsTest::render (sglr::Context& context, Surface& dst)
1343{
1344	int			width			= 128;
1345	int			height			= 128;
1346	deUint32	colorbuffer		= 1;
1347
1348	checkColorFormatSupport(context, getConfig().colorbufferFormat);
1349
1350	// Single colorbuffer
1351	if (getConfig().colorbufferType == GL_TEXTURE_2D)
1352	{
1353		context.bindTexture(GL_TEXTURE_2D, colorbuffer);
1354		context.texImage2D(GL_TEXTURE_2D, 0, getConfig().colorbufferFormat, width, height);
1355		context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1356	}
1357	else
1358	{
1359		DE_ASSERT(getConfig().colorbufferType == GL_RENDERBUFFER);
1360		context.bindRenderbuffer(GL_RENDERBUFFER, colorbuffer);
1361		context.renderbufferStorage(GL_RENDERBUFFER, getConfig().colorbufferFormat, width, height);
1362	}
1363
1364	// Multiple framebuffers sharing the colorbuffer
1365	for (int fbo = 1; fbo <= 3; fbo++)
1366	{
1367		context.bindFramebuffer(GL_FRAMEBUFFER, fbo);
1368
1369		if (getConfig().colorbufferType == GL_TEXTURE_2D)
1370			context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0);
1371		else
1372			context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer);
1373	}
1374
1375	context.bindFramebuffer(GL_FRAMEBUFFER, 1);
1376
1377	// Check completeness
1378	{
1379		GLenum status = context.checkFramebufferStatus(GL_FRAMEBUFFER);
1380		if (status != GL_FRAMEBUFFER_COMPLETE)
1381			throw FboIncompleteException(getConfig(), status, __FILE__, __LINE__);
1382	}
1383
1384	// Render to them
1385	context.viewport(0, 0, width, height);
1386	context.clearColor(0.0f, 0.0f, 1.0f, 1.0f);
1387	context.clear(GL_COLOR_BUFFER_BIT);
1388
1389	context.enable(GL_SCISSOR_TEST);
1390
1391	context.bindFramebuffer(GL_FRAMEBUFFER, 2);
1392	context.clearColor(0.6f, 0.0f, 0.0f, 1.0f);
1393	context.scissor(10, 10, 64, 64);
1394	context.clear(GL_COLOR_BUFFER_BIT);
1395	context.clearColor(0.0f, 0.6f, 0.0f, 1.0f);
1396	context.scissor(60, 60, 40, 20);
1397	context.clear(GL_COLOR_BUFFER_BIT);
1398
1399	context.bindFramebuffer(GL_FRAMEBUFFER, 3);
1400	context.clearColor(0.0f, 0.0f, 0.6f, 1.0f);
1401	context.scissor(20, 20, 100, 10);
1402	context.clear(GL_COLOR_BUFFER_BIT);
1403
1404	context.bindFramebuffer(GL_FRAMEBUFFER, 1);
1405	context.clearColor(0.6f, 0.0f, 0.6f, 1.0f);
1406	context.scissor(20, 20, 5, 100);
1407	context.clear(GL_COLOR_BUFFER_BIT);
1408
1409	context.disable(GL_SCISSOR_TEST);
1410
1411	if (getConfig().colorbufferType == GL_TEXTURE_2D)
1412	{
1413		SingleTex2DShader	shader;
1414		deUint32			shaderID = context.createProgram(&shader);
1415
1416		shader.setUnit(context, shaderID, 0);
1417
1418		context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1419		context.viewport(0, 0, context.getWidth(), context.getHeight());
1420		sglr::drawQuad(context, shaderID, Vec3(-0.9f, -0.9f, 0.0f), Vec3(0.9f, 0.9f, 0.0f));
1421		context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1422	}
1423	else
1424		context.readPixels(dst, 0, 0, width, height);
1425}
1426
1427class SharedDepthbufferTest : public FboRenderCase
1428{
1429public:
1430					SharedDepthbufferTest		(Context& context, const FboConfig& config);
1431	virtual			~SharedDepthbufferTest		(void) {}
1432
1433	static bool		isConfigSupported			(const FboConfig& config);
1434	void			render						(sglr::Context& context, Surface& dst);
1435};
1436
1437SharedDepthbufferTest::SharedDepthbufferTest (Context& context, const FboConfig& config)
1438	: FboRenderCase(context, config.getName().c_str(), "Shared depthbuffer", config)
1439{
1440}
1441
1442bool SharedDepthbufferTest::isConfigSupported (const FboConfig& config)
1443{
1444	return config.depthbufferType == GL_RENDERBUFFER;
1445}
1446
1447void SharedDepthbufferTest::render (sglr::Context& context, Surface& dst)
1448{
1449	SingleTex2DShader	texShader;
1450	FlatColorShader		colorShader;
1451	deUint32			texShaderID		= context.createProgram(&texShader);
1452	deUint32			colorShaderID	= context.createProgram(&colorShader);
1453	int					width			= 128;
1454	int					height			= 128;
1455	bool				stencil			= getConfig().stencilbufferType != GL_NONE;
1456
1457	// Setup shaders
1458	texShader.setUnit(context, texShaderID, 0);
1459	colorShader.setColor(context, colorShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1460
1461	// Textures
1462	deUint32 metaballsTex	= 5;
1463	deUint32 quadsTex		= 6;
1464	createMetaballsTex2D(context, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1465	createQuadsTex2D(context, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1466
1467	context.viewport(0, 0, width, height);
1468
1469	// Fbo A
1470	Framebuffer fboA(context, getConfig(), width, height);
1471	fboA.checkCompleteness();
1472
1473	// Fbo B
1474	FboConfig cfg = getConfig();
1475	cfg.depthbufferType		= GL_NONE;
1476	cfg.depthbufferFormat	= GL_NONE;
1477	Framebuffer fboB(context, cfg, width, height);
1478
1479	// Bind depth buffer from fbo A to fbo B
1480	DE_ASSERT(fboA.getConfig().depthbufferType == GL_RENDERBUFFER);
1481	context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer());
1482	context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fboA.getDepthbuffer());
1483
1484	// Clear fbo B color to red and stencil to 1
1485	context.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
1486	context.clearStencil(1);
1487	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1488
1489	// Enable depth test.
1490	context.enable(GL_DEPTH_TEST);
1491
1492	// Render quad to fbo A
1493	context.bindFramebuffer(GL_FRAMEBUFFER, fboA.getFramebuffer());
1494	context.bindTexture(GL_TEXTURE_2D, quadsTex);
1495	context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1496	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1497	sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1498
1499	// Render metaballs to fbo B
1500	context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer());
1501	context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1502	sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f));
1503
1504	context.disable(GL_DEPTH_TEST);
1505
1506	if (stencil)
1507	{
1508		// Clear subset of stencil buffer to 0
1509		context.enable(GL_SCISSOR_TEST);
1510		context.scissor(10, 10, 12, 25);
1511		context.clearStencil(0);
1512		context.clear(GL_STENCIL_BUFFER_BIT);
1513		context.disable(GL_SCISSOR_TEST);
1514
1515		// Render quad with stencil mask == 0
1516		context.enable(GL_STENCIL_TEST);
1517		context.stencilFunc(GL_EQUAL, 0, 0xffu);
1518		sglr::drawQuad(context, colorShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1519		context.disable(GL_STENCIL_TEST);
1520	}
1521
1522	if (getConfig().colorbufferType == GL_TEXTURE_2D)
1523	{
1524		// Render both to screen
1525		context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1526		context.viewport(0, 0, context.getWidth(), context.getHeight());
1527		context.bindTexture(GL_TEXTURE_2D, fboA.getColorbuffer());
1528		sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(0.0f, 1.0f, 0.0f));
1529		context.bindTexture(GL_TEXTURE_2D, fboB.getColorbuffer());
1530		sglr::drawQuad(context, texShaderID, Vec3(0.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1531
1532		context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1533	}
1534	else
1535	{
1536		// Read results from fbo B
1537		context.readPixels(dst, 0, 0, width, height);
1538	}
1539}
1540
1541class TexSubImageAfterRenderTest : public FboRenderCase
1542{
1543public:
1544					TexSubImageAfterRenderTest		(Context& context, const FboConfig& config);
1545	virtual			~TexSubImageAfterRenderTest		(void) {}
1546
1547	static bool		isConfigSupported				(const FboConfig& config);
1548	void			render							(sglr::Context& context, Surface& dst);
1549};
1550
1551TexSubImageAfterRenderTest::TexSubImageAfterRenderTest (Context& context, const FboConfig& config)
1552	: FboRenderCase(context, (string("after_render_") + config.getName()).c_str(), "TexSubImage after rendering to texture", config)
1553{
1554}
1555
1556bool TexSubImageAfterRenderTest::isConfigSupported (const FboConfig& config)
1557{
1558	return config.colorbufferType == GL_TEXTURE_2D &&
1559		   (config.colorbufferFormat == GL_RGB || config.colorbufferFormat == GL_RGBA) &&
1560		   config.depthbufferType == GL_NONE &&
1561		   config.stencilbufferType == GL_NONE;
1562}
1563
1564void TexSubImageAfterRenderTest::render (sglr::Context& context, Surface& dst)
1565{
1566	SingleTex2DShader	shader;
1567	deUint32			shaderID	= context.createProgram(&shader);
1568	bool				isRGBA		= getConfig().colorbufferFormat == GL_RGBA;
1569
1570	tcu::TextureLevel fourQuads(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), 64, 64);
1571	tcu::fillWithRGBAQuads(fourQuads.getAccess());
1572
1573	tcu::TextureLevel metaballs(tcu::TextureFormat(isRGBA ? tcu::TextureFormat::RGBA : tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), 64, 64);
1574	tcu::fillWithMetaballs(metaballs.getAccess(), 5, 3);
1575
1576	shader.setUnit(context, shaderID, 0);
1577
1578	deUint32 fourQuadsTex = 1;
1579	context.bindTexture(GL_TEXTURE_2D, fourQuadsTex);
1580	context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1581	context.texImage2D(GL_TEXTURE_2D, 0, GL_RGB, 64, 64, 0, GL_RGB, GL_UNSIGNED_BYTE, fourQuads.getAccess().getDataPtr());
1582
1583	context.bindFramebuffer(GL_FRAMEBUFFER, 1);
1584
1585	deUint32 fboTex = 2;
1586	context.bindTexture(GL_TEXTURE_2D, fboTex);
1587	context.texImage2D(GL_TEXTURE_2D, 0, isRGBA ? GL_RGBA : GL_RGB, 128, 128);
1588	context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1589	context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0);
1590
1591	// Render to fbo
1592	context.viewport(0, 0, 128, 128);
1593	context.bindTexture(GL_TEXTURE_2D, fourQuadsTex);
1594	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1595
1596	// Update texture using TexSubImage2D
1597	context.bindTexture(GL_TEXTURE_2D, fboTex);
1598	context.texSubImage2D(GL_TEXTURE_2D, 0, 32, 32, 64, 64, isRGBA ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, metaballs.getAccess().getDataPtr());
1599
1600	// Draw to screen
1601	context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1602	context.viewport(0, 0, context.getWidth(), context.getHeight());
1603	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1604	context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1605}
1606
1607class TexSubImageBetweenRenderTest : public FboRenderCase
1608{
1609public:
1610					TexSubImageBetweenRenderTest		(Context& context, const FboConfig& config);
1611	virtual			~TexSubImageBetweenRenderTest		(void) {}
1612
1613	static bool		isConfigSupported					(const FboConfig& config);
1614	void			render								(sglr::Context& context, Surface& dst);
1615};
1616
1617TexSubImageBetweenRenderTest::TexSubImageBetweenRenderTest (Context& context, const FboConfig& config)
1618	: FboRenderCase(context, (string("between_render_") + config.getName()).c_str(), "TexSubImage between rendering calls", config)
1619{
1620}
1621
1622bool TexSubImageBetweenRenderTest::isConfigSupported (const FboConfig& config)
1623{
1624	return config.colorbufferType == GL_TEXTURE_2D &&
1625		   (config.colorbufferFormat == GL_RGB || config.colorbufferFormat == GL_RGBA) &&
1626		   config.depthbufferType == GL_NONE &&
1627		   config.stencilbufferType == GL_NONE;
1628}
1629
1630void TexSubImageBetweenRenderTest::render (sglr::Context& context, Surface& dst)
1631{
1632	SingleTex2DShader	shader;
1633	deUint32			shaderID	= context.createProgram(&shader);
1634	bool				isRGBA		= getConfig().colorbufferFormat == GL_RGBA;
1635
1636	tcu::TextureLevel fourQuads(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), 64, 64);
1637	tcu::fillWithRGBAQuads(fourQuads.getAccess());
1638
1639	tcu::TextureLevel metaballs(tcu::TextureFormat(isRGBA ? tcu::TextureFormat::RGBA : tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), 64, 64);
1640	tcu::fillWithMetaballs(metaballs.getAccess(), 5, 3);
1641
1642	tcu::TextureLevel metaballs2(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 64, 64);
1643	tcu::fillWithMetaballs(metaballs2.getAccess(), 5, 4);
1644
1645	deUint32 metaballsTex = 3;
1646	context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1647	context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1648	context.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, metaballs2.getAccess().getDataPtr());
1649
1650	deUint32 fourQuadsTex = 1;
1651	context.bindTexture(GL_TEXTURE_2D, fourQuadsTex);
1652	context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1653	context.texImage2D(GL_TEXTURE_2D, 0, GL_RGB, 64, 64, 0, GL_RGB, GL_UNSIGNED_BYTE, fourQuads.getAccess().getDataPtr());
1654
1655	context.bindFramebuffer(GL_FRAMEBUFFER, 1);
1656
1657	deUint32 fboTex = 2;
1658	context.bindTexture(GL_TEXTURE_2D, fboTex);
1659	context.texImage2D(GL_TEXTURE_2D, 0, isRGBA ? GL_RGBA : GL_RGB, 128, 128);
1660	context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1661	context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0);
1662
1663	shader.setUnit(context, shaderID, 0);
1664
1665	// Render to fbo
1666	context.viewport(0, 0, 128, 128);
1667	context.bindTexture(GL_TEXTURE_2D, fourQuadsTex);
1668	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1669
1670	// Update texture using TexSubImage2D
1671	context.bindTexture(GL_TEXTURE_2D, fboTex);
1672	context.texSubImage2D(GL_TEXTURE_2D, 0, 32, 32, 64, 64, isRGBA ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, metaballs.getAccess().getDataPtr());
1673
1674	// Render again to fbo
1675	context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1676	context.enable(GL_BLEND);
1677	context.blendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
1678	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1679	context.disable(GL_BLEND);
1680
1681	// Draw to screen
1682	context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1683	context.viewport(0, 0, context.getWidth(), context.getHeight());
1684	context.bindTexture(GL_TEXTURE_2D, fboTex);
1685	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1686
1687	context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1688}
1689
1690class ResizeTest : public FboRenderCase
1691{
1692public:
1693					ResizeTest				(Context& context, const FboConfig& config);
1694	virtual			~ResizeTest				(void) {}
1695
1696	void			render					(sglr::Context& context, Surface& dst);
1697};
1698
1699ResizeTest::ResizeTest (Context& context, const FboConfig& config)
1700	: FboRenderCase(context, config.getName().c_str(), "Resize framebuffer", config)
1701{
1702}
1703
1704void ResizeTest::render (sglr::Context& context, Surface& dst)
1705{
1706	SingleTex2DShader	texShader;
1707	FlatColorShader		colorShader;
1708	deUint32			texShaderID		= context.createProgram(&texShader);
1709	deUint32			colorShaderID	= context.createProgram(&colorShader);
1710	deUint32			quadsTex		= 1;
1711	deUint32			metaballsTex	= 2;
1712	bool				depth			= getConfig().depthbufferType	 != GL_NONE;
1713	bool				stencil			= getConfig().stencilbufferType	 != GL_NONE;
1714
1715	createQuadsTex2D(context, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1716	createMetaballsTex2D(context, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 32, 32);
1717
1718	Framebuffer fbo(context, getConfig(), 128, 128);
1719	fbo.checkCompleteness();
1720
1721	// Setup shaders
1722	texShader.setUnit(context, texShaderID, 0);
1723	colorShader.setColor(context, colorShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1724
1725	// Render quads
1726	context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1727	context.viewport(0, 0, 128, 128);
1728	context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1729	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1730	context.bindTexture(GL_TEXTURE_2D, quadsTex);
1731	sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1732
1733	if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D)
1734	{
1735		// Render fbo to screen
1736		context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1737		context.viewport(0, 0, context.getWidth(), context.getHeight());
1738		context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
1739		sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1740
1741		// Restore binding
1742		context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1743	}
1744
1745	int newWidth	= 64;
1746	int newHeight	= 32;
1747
1748	// Resize buffers
1749	switch (fbo.getConfig().colorbufferType)
1750	{
1751		case GL_TEXTURE_2D:
1752			context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
1753			context.texImage2D(GL_TEXTURE_2D, 0, fbo.getConfig().colorbufferFormat, newWidth, newHeight);
1754			break;
1755
1756		case GL_RENDERBUFFER:
1757			context.bindRenderbuffer(GL_RENDERBUFFER, fbo.getColorbuffer());
1758			context.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().colorbufferFormat, newWidth, newHeight);
1759			break;
1760
1761		default:
1762			DE_ASSERT(false);
1763	}
1764
1765	if (depth)
1766	{
1767		DE_ASSERT(fbo.getConfig().depthbufferType == GL_RENDERBUFFER);
1768		context.bindRenderbuffer(GL_RENDERBUFFER, fbo.getDepthbuffer());
1769		context.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().depthbufferFormat, newWidth, newHeight);
1770	}
1771
1772	if (stencil)
1773	{
1774		DE_ASSERT(fbo.getConfig().stencilbufferType == GL_RENDERBUFFER);
1775		context.bindRenderbuffer(GL_RENDERBUFFER, fbo.getStencilbuffer());
1776		context.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().stencilbufferFormat, newWidth, newHeight);
1777	}
1778
1779	// Render to resized fbo
1780	context.viewport(0, 0, newWidth, newHeight);
1781	context.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
1782	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1783
1784	context.enable(GL_DEPTH_TEST);
1785
1786	context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1787	sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
1788
1789	context.bindTexture(GL_TEXTURE_2D, quadsTex);
1790	sglr::drawQuad(context, texShaderID, Vec3(0.0f, 0.0f, -1.0f), Vec3(+1.0f, +1.0f, 1.0f));
1791
1792	context.disable(GL_DEPTH_TEST);
1793
1794	if (stencil)
1795	{
1796		context.enable(GL_SCISSOR_TEST);
1797		context.scissor(10, 10, 5, 15);
1798		context.clearStencil(1);
1799		context.clear(GL_STENCIL_BUFFER_BIT);
1800		context.disable(GL_SCISSOR_TEST);
1801
1802		context.enable(GL_STENCIL_TEST);
1803		context.stencilFunc(GL_EQUAL, 1, 0xffu);
1804		sglr::drawQuad(context, colorShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
1805		context.disable(GL_STENCIL_TEST);
1806	}
1807
1808	if (getConfig().colorbufferType == GL_TEXTURE_2D)
1809	{
1810		context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1811		context.viewport(0, 0, context.getWidth(), context.getHeight());
1812		context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
1813		sglr::drawQuad(context, texShaderID, Vec3(-0.5f, -0.5f, 0.0f), Vec3(0.5f, 0.5f, 0.0f));
1814		context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1815	}
1816	else
1817		context.readPixels(dst, 0, 0, newWidth, newHeight);
1818}
1819
1820template <GLenum Buffers>
1821class RecreateBuffersTest : public FboRenderCase
1822{
1823public:
1824					RecreateBuffersTest			(Context& context, const FboConfig& config, bool rebind);
1825	virtual			~RecreateBuffersTest		(void) {}
1826
1827	static bool		isConfigSupported			(const FboConfig& config);
1828	void			render						(sglr::Context& context, Surface& dst);
1829
1830private:
1831	bool			m_rebind;
1832};
1833
1834template <GLenum Buffers>
1835class RecreateBuffersNoRebindTest : public RecreateBuffersTest<Buffers>
1836{
1837public:
1838	RecreateBuffersNoRebindTest (Context& context, const FboConfig& config)
1839		: RecreateBuffersTest<Buffers>(context, config, false)
1840	{
1841	}
1842};
1843
1844template <GLenum Buffers>
1845class RecreateBuffersRebindTest : public RecreateBuffersTest<Buffers>
1846{
1847public:
1848	RecreateBuffersRebindTest (Context& context, const FboConfig& config)
1849		: RecreateBuffersTest<Buffers>(context, config, true)
1850	{
1851	}
1852};
1853
1854template <GLenum Buffers>
1855RecreateBuffersTest<Buffers>::RecreateBuffersTest (Context& context, const FboConfig& config, bool rebind)
1856	: FboRenderCase		(context, (string(rebind ? "rebind_" : "no_rebind_") + config.getName()).c_str(), "Recreate buffers", config)
1857	, m_rebind			(rebind)
1858{
1859}
1860
1861template <GLenum Buffers>
1862bool RecreateBuffersTest<Buffers>::isConfigSupported (const FboConfig& config)
1863{
1864	if ((Buffers & GL_COLOR_BUFFER_BIT) && config.colorbufferType == GL_NONE)
1865		return false;
1866	if ((Buffers & GL_DEPTH_BUFFER_BIT) && config.depthbufferType == GL_NONE)
1867		return false;
1868	if ((Buffers & GL_STENCIL_BUFFER_BIT) && config.stencilbufferType == GL_NONE)
1869		return false;
1870	return true;
1871}
1872
1873template <GLenum Buffers>
1874void RecreateBuffersTest<Buffers>::render (sglr::Context& ctx, Surface& dst)
1875{
1876	SingleTex2DShader	texShader;
1877	deUint32			texShaderID		= ctx.createProgram(&texShader);
1878	int					width			= 128;
1879	int					height			= 128;
1880	deUint32			metaballsTex	= 1;
1881	deUint32			quadsTex		= 2;
1882	bool				stencil			= getConfig().stencilbufferType != GL_NONE;
1883
1884	createQuadsTex2D(ctx, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1885	createMetaballsTex2D(ctx, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1886
1887	Framebuffer fbo(ctx, getConfig(), width, height);
1888	fbo.checkCompleteness();
1889
1890	// Setup shader
1891	texShader.setUnit(ctx, texShaderID, 0);
1892
1893	// Draw scene
1894	ctx.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1895	ctx.viewport(0, 0, width, height);
1896	ctx.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
1897	ctx.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1898
1899	ctx.enable(GL_DEPTH_TEST);
1900
1901	ctx.bindTexture(GL_TEXTURE_2D, quadsTex);
1902	sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1903
1904	if (stencil)
1905	{
1906		ctx.enable(GL_SCISSOR_TEST);
1907		ctx.scissor(width/4, height/4, width/2, height/2);
1908		ctx.clearStencil(1);
1909		ctx.clear(GL_STENCIL_BUFFER_BIT);
1910		ctx.disable(GL_SCISSOR_TEST);
1911	}
1912
1913	// Recreate buffers
1914	if (!m_rebind)
1915		ctx.bindFramebuffer(GL_FRAMEBUFFER, 0);
1916
1917	if (Buffers & GL_COLOR_BUFFER_BIT)
1918	{
1919		deUint32 colorbuf = fbo.getColorbuffer();
1920		switch (fbo.getConfig().colorbufferType)
1921		{
1922			case GL_TEXTURE_2D:
1923				ctx.deleteTextures(1, &colorbuf);
1924				ctx.bindTexture(GL_TEXTURE_2D, colorbuf);
1925				ctx.texImage2D(GL_TEXTURE_2D, 0, fbo.getConfig().colorbufferFormat, width, height);
1926				ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1927
1928				if (m_rebind)
1929					ctx.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuf, 0);
1930				break;
1931
1932			case GL_RENDERBUFFER:
1933				ctx.deleteRenderbuffers(1, &colorbuf);
1934				ctx.bindRenderbuffer(GL_RENDERBUFFER, colorbuf);
1935				ctx.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().colorbufferFormat, width, height);
1936
1937				if (m_rebind)
1938					ctx.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuf);
1939				break;
1940
1941			default:
1942				DE_ASSERT(false);
1943		}
1944	}
1945
1946	if (Buffers & GL_DEPTH_BUFFER_BIT)
1947	{
1948		deUint32 depthbuf = fbo.getDepthbuffer();
1949		DE_ASSERT(fbo.getConfig().depthbufferType == GL_RENDERBUFFER);
1950
1951		ctx.deleteRenderbuffers(1, &depthbuf);
1952		ctx.bindRenderbuffer(GL_RENDERBUFFER, depthbuf);
1953		ctx.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().depthbufferFormat, width, height);
1954
1955		if (m_rebind)
1956			ctx.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthbuf);
1957	}
1958
1959	if (Buffers & GL_STENCIL_BUFFER_BIT)
1960	{
1961		deUint32 stencilbuf = fbo.getStencilbuffer();
1962		DE_ASSERT(fbo.getConfig().stencilbufferType == GL_RENDERBUFFER);
1963
1964		ctx.deleteRenderbuffers(1, &stencilbuf);
1965		ctx.bindRenderbuffer(GL_RENDERBUFFER, stencilbuf);
1966		ctx.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().stencilbufferFormat, width, height);
1967
1968		if (m_rebind)
1969			ctx.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencilbuf);
1970	}
1971
1972	if (!m_rebind)
1973		ctx.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1974
1975	ctx.clearColor(0.0f, 0.0f, 1.0f, 0.0f);
1976	ctx.clearStencil(0);
1977	ctx.clear(Buffers); // \note Clear only buffers that were re-created
1978
1979	if (stencil)
1980	{
1981		// \note Stencil test enabled only if we have stencil buffer
1982		ctx.enable(GL_STENCIL_TEST);
1983		ctx.stencilFunc(GL_EQUAL, 0, 0xffu);
1984	}
1985	ctx.bindTexture(GL_TEXTURE_2D, metaballsTex);
1986	sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 1.0f), Vec3(1.0f, 1.0f, -1.0f));
1987	if (stencil)
1988		ctx.disable(GL_STENCIL_TEST);
1989
1990	ctx.disable(GL_DEPTH_TEST);
1991
1992	// Read from fbo
1993	ctx.readPixels(dst, 0, 0, width, height);
1994}
1995
1996class RepeatedClearCase : public FboRenderCase
1997{
1998private:
1999	static FboConfig makeConfig (deUint32 format)
2000	{
2001		FboConfig cfg;
2002		cfg.colorbufferType		= GL_TEXTURE_2D;
2003		cfg.colorbufferFormat	= format;
2004		cfg.depthbufferType		= GL_NONE;
2005		cfg.stencilbufferType	= GL_NONE;
2006		return cfg;
2007	}
2008
2009public:
2010	RepeatedClearCase (Context& context, deUint32 format)
2011		: FboRenderCase(context, makeConfig(format).getName().c_str(), "Repeated clears", makeConfig(format))
2012	{
2013	}
2014
2015protected:
2016	void render (sglr::Context& ctx, Surface& dst)
2017	{
2018		const int						numRowsCols		= 4;
2019		const int						cellSize		= 16;
2020		const int						fboSizes[]		= { cellSize, cellSize*numRowsCols };
2021
2022		SingleTex2DShader				fboBlitShader;
2023		const deUint32					fboBlitShaderID	= ctx.createProgram(&fboBlitShader);
2024
2025		de::Random						rnd				(18169662);
2026		deUint32						fbos[]			= { 0, 0 };
2027		deUint32						textures[]		= { 0, 0 };
2028
2029		ctx.genFramebuffers(2, &fbos[0]);
2030		ctx.genTextures(2, &textures[0]);
2031
2032		for (int fboNdx = 0; fboNdx < DE_LENGTH_OF_ARRAY(fbos); fboNdx++)
2033		{
2034			ctx.bindTexture(GL_TEXTURE_2D, textures[fboNdx]);
2035			ctx.texImage2D(GL_TEXTURE_2D, 0, getConfig().colorbufferFormat, fboSizes[fboNdx], fboSizes[fboNdx], 0,
2036						   getConfig().colorbufferFormat, GL_UNSIGNED_BYTE, DE_NULL);
2037			ctx.texParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
2038			ctx.texParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
2039			ctx.texParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	GL_NEAREST);
2040			ctx.texParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	GL_NEAREST);
2041
2042			ctx.bindFramebuffer(GL_FRAMEBUFFER, fbos[fboNdx]);
2043			ctx.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[fboNdx], 0);
2044
2045			{
2046				const GLenum status = ctx.checkFramebufferStatus(GL_FRAMEBUFFER);
2047				if (status != GL_FRAMEBUFFER_COMPLETE)
2048					throw FboIncompleteException(getConfig(), status, __FILE__, __LINE__);
2049			}
2050		}
2051
2052		// larger fbo bound -- clear to transparent black
2053		ctx.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
2054		ctx.clear(GL_COLOR_BUFFER_BIT);
2055
2056		fboBlitShader.setUnit(ctx, fboBlitShaderID, 0);
2057		ctx.bindTexture(GL_TEXTURE_2D, textures[0]);
2058
2059		for (int cellY = 0; cellY < numRowsCols; cellY++)
2060		for (int cellX = 0; cellX < numRowsCols; cellX++)
2061		{
2062			const float	r	= rnd.getFloat();
2063			const float	g	= rnd.getFloat();
2064			const float	b	= rnd.getFloat();
2065			const float	a	= rnd.getFloat();
2066
2067			ctx.bindFramebuffer(GL_FRAMEBUFFER, fbos[0]);
2068			ctx.clearColor(r, g, b, a);
2069			ctx.clear(GL_COLOR_BUFFER_BIT);
2070
2071			ctx.bindFramebuffer(GL_FRAMEBUFFER, fbos[1]);
2072			ctx.viewport(cellX*cellSize, cellY*cellSize, cellSize, cellSize);
2073			sglr::drawQuad(ctx, fboBlitShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
2074		}
2075
2076		ctx.readPixels(dst, 0, 0, fboSizes[1], fboSizes[1]);
2077	}
2078};
2079
2080} // FboCases
2081
2082FboRenderTestGroup::FboRenderTestGroup (Context& context)
2083	: TestCaseGroup(context, "render", "Rendering Tests")
2084{
2085}
2086
2087FboRenderTestGroup::~FboRenderTestGroup (void)
2088{
2089}
2090
2091namespace
2092{
2093
2094struct TypeFormatPair
2095{
2096	GLenum		type;
2097	GLenum		format;
2098};
2099
2100template <typename CaseType>
2101void addChildVariants (deqp::gles2::TestCaseGroup* group)
2102{
2103	TypeFormatPair colorbufferConfigs[] =
2104	{
2105//		{ GL_TEXTURE_2D,	GL_ALPHA },
2106//		{ GL_TEXTURE_2D,	GL_LUMINANCE },
2107//		{ GL_TEXTURE_2D,	GL_LUMINANCE_ALPHA },
2108		{ GL_TEXTURE_2D,	GL_RGB },
2109		{ GL_TEXTURE_2D,	GL_RGBA },
2110		{ GL_RENDERBUFFER,	GL_RGB565 },
2111		{ GL_RENDERBUFFER,	GL_RGB5_A1 },
2112		{ GL_RENDERBUFFER,	GL_RGBA4 },
2113//		{ GL_RENDERBUFFER,	GL_RGBA16F },
2114//		{ GL_RENDERBUFFER,	GL_RGB16F }
2115	};
2116	TypeFormatPair depthbufferConfigs[] =
2117	{
2118		{ GL_NONE,			GL_NONE },
2119		{ GL_RENDERBUFFER,	GL_DEPTH_COMPONENT16 }
2120	};
2121	TypeFormatPair stencilbufferConfigs[] =
2122	{
2123		{ GL_NONE,			GL_NONE },
2124		{ GL_RENDERBUFFER,	GL_STENCIL_INDEX8 }
2125	};
2126
2127	for (int colorbufferNdx = 0; colorbufferNdx < DE_LENGTH_OF_ARRAY(colorbufferConfigs); colorbufferNdx++)
2128	for (int depthbufferNdx = 0; depthbufferNdx < DE_LENGTH_OF_ARRAY(depthbufferConfigs); depthbufferNdx++)
2129	for (int stencilbufferNdx = 0; stencilbufferNdx < DE_LENGTH_OF_ARRAY(stencilbufferConfigs); stencilbufferNdx++)
2130	{
2131		FboConfig config;
2132		config.colorbufferType		= colorbufferConfigs[colorbufferNdx].type;
2133		config.colorbufferFormat	= colorbufferConfigs[colorbufferNdx].format;
2134		config.depthbufferType		= depthbufferConfigs[depthbufferNdx].type;
2135		config.depthbufferFormat	= depthbufferConfigs[depthbufferNdx].format;
2136		config.stencilbufferType	= stencilbufferConfigs[stencilbufferNdx].type;
2137		config.stencilbufferFormat	= stencilbufferConfigs[stencilbufferNdx].format;
2138
2139		if (CaseType::isConfigSupported(config))
2140			group->addChild(new CaseType(group->getContext(), config));
2141	}
2142}
2143
2144template <typename CaseType>
2145void createChildGroup (deqp::gles2::TestCaseGroup* parent, const char* name, const char* description)
2146{
2147	deqp::gles2::TestCaseGroup* tmpGroup = new deqp::gles2::TestCaseGroup(parent->getContext(), name, description);
2148	parent->addChild(tmpGroup);
2149	addChildVariants<CaseType>(tmpGroup);
2150}
2151
2152template <GLbitfield Buffers>
2153void createRecreateBuffersGroup (deqp::gles2::TestCaseGroup* parent, const char* name, const char* description)
2154{
2155	deqp::gles2::TestCaseGroup* tmpGroup = new deqp::gles2::TestCaseGroup(parent->getContext(), name, description);
2156	parent->addChild(tmpGroup);
2157	addChildVariants<FboCases::RecreateBuffersRebindTest<Buffers> >		(tmpGroup);
2158	addChildVariants<FboCases::RecreateBuffersNoRebindTest<Buffers> >	(tmpGroup);
2159}
2160
2161} // anonymous
2162
2163void FboRenderTestGroup::init (void)
2164{
2165	createChildGroup<FboCases::ColorClearsTest>					(this, "color_clear",		"Color buffer clears");
2166	createChildGroup<FboCases::StencilClearsTest>				(this, "stencil_clear",		"Stencil buffer clears");
2167
2168	deqp::gles2::TestCaseGroup* colorGroup = new deqp::gles2::TestCaseGroup(m_context, "color", "Color buffer tests");
2169	addChild(colorGroup);
2170	addChildVariants<FboCases::MixTest>			(colorGroup);
2171	addChildVariants<FboCases::MixNpotTest>		(colorGroup);
2172	addChildVariants<FboCases::BlendTest>		(colorGroup);
2173	addChildVariants<FboCases::BlendNpotTest>	(colorGroup);
2174
2175	deqp::gles2::TestCaseGroup* depthGroup = new deqp::gles2::TestCaseGroup(m_context, "depth", "Depth bufer tests");
2176	addChild(depthGroup);
2177	addChildVariants<FboCases::IntersectingQuadsTest>		(depthGroup);
2178	addChildVariants<FboCases::IntersectingQuadsNpotTest>	(depthGroup);
2179
2180	deqp::gles2::TestCaseGroup* stencilGroup = new deqp::gles2::TestCaseGroup(m_context, "stencil", "Stencil buffer tests");
2181	addChild(stencilGroup);
2182	addChildVariants<FboCases::StencilTest>		(stencilGroup);
2183	addChildVariants<FboCases::StencilNpotTest>	(stencilGroup);
2184
2185	createChildGroup<FboCases::SharedColorbufferClearsTest>		(this, "shared_colorbuffer_clear",	"Shared colorbuffer clears");
2186	createChildGroup<FboCases::SharedColorbufferTest>			(this, "shared_colorbuffer",		"Shared colorbuffer tests");
2187	createChildGroup<FboCases::SharedDepthbufferTest>			(this, "shared_depthbuffer",		"Shared depthbuffer tests");
2188	createChildGroup<FboCases::ResizeTest>						(this, "resize",					"FBO resize tests");
2189
2190	createRecreateBuffersGroup<GL_COLOR_BUFFER_BIT>				(this, "recreate_colorbuffer",		"Recreate colorbuffer tests");
2191	createRecreateBuffersGroup<GL_DEPTH_BUFFER_BIT>				(this, "recreate_depthbuffer",		"Recreate depthbuffer tests");
2192	createRecreateBuffersGroup<GL_STENCIL_BUFFER_BIT>			(this, "recreate_stencilbuffer",	"Recreate stencilbuffer tests");
2193
2194	deqp::gles2::TestCaseGroup* texSubImageGroup = new deqp::gles2::TestCaseGroup(m_context, "texsubimage", "TexSubImage interop with FBO colorbuffer texture");
2195	addChild(texSubImageGroup);
2196	addChildVariants<FboCases::TexSubImageAfterRenderTest>		(texSubImageGroup);
2197	addChildVariants<FboCases::TexSubImageBetweenRenderTest>	(texSubImageGroup);
2198
2199	{
2200		tcu::TestCaseGroup* const repeatedClearGroup = new tcu::TestCaseGroup(m_testCtx, "repeated_clear", "Repeated FBO clears");
2201		addChild(repeatedClearGroup);
2202
2203		repeatedClearGroup->addChild(new FboCases::RepeatedClearCase(m_context, GL_RGB));
2204		repeatedClearGroup->addChild(new FboCases::RepeatedClearCase(m_context, GL_RGBA));
2205	}
2206}
2207
2208} // Functional
2209} // gles2
2210} // deqp
2211