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.03f;
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		// Read from fbo
718		context.readPixels(dst, 0, 0, width, height);
719	}
720}
721
722class IntersectingQuadsTest : public FboRenderCase
723{
724public:
725					IntersectingQuadsTest			(Context& context, const FboConfig& config, bool npot = false);
726	virtual			~IntersectingQuadsTest			(void) {}
727
728	virtual void	render							(sglr::Context& context, Surface& dst);
729
730	static bool		isConfigSupported				(const FboConfig& config);
731
732private:
733	int				m_fboWidth;
734	int				m_fboHeight;
735};
736
737class IntersectingQuadsNpotTest : public IntersectingQuadsTest
738{
739public:
740	IntersectingQuadsNpotTest (Context& context, const FboConfig& config)
741		: IntersectingQuadsTest(context, config, true)
742	{
743	}
744};
745
746IntersectingQuadsTest::IntersectingQuadsTest (Context& context, const FboConfig& config, bool npot)
747	: FboRenderCase	(context, (string(npot ? "npot_" : "") + config.getName()).c_str(), "Intersecting textured quads", config)
748	, m_fboWidth	(npot ? 127 : 128)
749	, m_fboHeight	(npot ?  95 : 128)
750{
751}
752
753bool IntersectingQuadsTest::isConfigSupported (const FboConfig& config)
754{
755	// \note Disabled for stencil configurations since doesn't exercise stencil buffer
756	return config.depthbufferType	!= GL_NONE &&
757		   config.stencilbufferType	== GL_NONE;
758}
759
760void IntersectingQuadsTest::render (sglr::Context& ctx, Surface& dst)
761{
762	SingleTex2DShader	texShader;
763	deUint32			texShaderID = ctx.createProgram(&texShader);
764
765	deUint32 metaballsTex	= 1;
766	deUint32 quadsTex		= 2;
767
768	createMetaballsTex2D(ctx, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
769	createQuadsTex2D(ctx, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
770
771	int width	= m_fboWidth;
772	int height	= m_fboHeight;
773	Framebuffer fbo(ctx, getConfig(), width, height);
774	fbo.checkCompleteness();
775
776	// Setup shaders
777	texShader.setUnit(ctx, texShaderID, 0);
778
779	// Draw scene
780	ctx.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
781	ctx.viewport(0, 0, width, height);
782	ctx.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
783	ctx.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
784
785	ctx.enable(GL_DEPTH_TEST);
786
787	ctx.bindTexture(GL_TEXTURE_2D, metaballsTex);
788	sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f));
789
790	ctx.bindTexture(GL_TEXTURE_2D, quadsTex);
791	sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 1.0f), Vec3(1.0f, 1.0f, -1.0f));
792
793	ctx.disable(GL_DEPTH_TEST);
794
795	if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D)
796	{
797		// Unbind fbo
798		ctx.bindFramebuffer(GL_FRAMEBUFFER, 0);
799
800		// Draw to screen
801		ctx.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
802		ctx.viewport(0, 0, ctx.getWidth(), ctx.getHeight());
803		sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
804
805		// Read from screen
806		ctx.readPixels(dst, 0, 0, ctx.getWidth(), ctx.getHeight());
807	}
808	else
809	{
810		// Read from fbo
811		ctx.readPixels(dst, 0, 0, width, height);
812	}
813}
814
815class MixTest : public FboRenderCase
816{
817public:
818						MixTest				(Context& context, const FboConfig& config, bool npot = false);
819	virtual				~MixTest			(void) {}
820
821	void				render				(sglr::Context& context, Surface& dst);
822
823	static bool			isConfigSupported	(const FboConfig& config);
824
825private:
826	int					m_fboAWidth;
827	int					m_fboAHeight;
828	int					m_fboBWidth;
829	int					m_fboBHeight;
830};
831
832class MixNpotTest : public MixTest
833{
834public:
835	MixNpotTest (Context& context, const FboConfig& config)
836		: MixTest(context, config, true)
837	{
838	}
839};
840
841MixTest::MixTest (Context& context, const FboConfig& config, bool npot)
842	: FboRenderCase	(context, (string(npot ? "mix_npot_" : "mix_") + config.getName()).c_str(), "Use two fbos as sources in draw operation", config)
843	, m_fboAWidth	(npot ? 127 : 128)
844	, m_fboAHeight	(npot ?  95 : 128)
845	, m_fboBWidth	(npot ?  55 :  64)
846	, m_fboBHeight	(npot ?  63 :  64)
847{
848}
849
850bool MixTest::isConfigSupported (const FboConfig& config)
851{
852	// \note Disabled for stencil configurations since doesn't exercise stencil buffer
853	return config.colorbufferType	== GL_TEXTURE_2D &&
854		   config.stencilbufferType	== GL_NONE;
855}
856
857void MixTest::render (sglr::Context& context, Surface& dst)
858{
859	SingleTex2DShader	singleTexShader;
860	MixTexturesShader	mixShader;
861
862	deUint32			singleTexShaderID	= context.createProgram(&singleTexShader);
863	deUint32			mixShaderID			= context.createProgram(&mixShader);
864
865	// Texture with metaballs
866	deUint32 metaballsTex = 1;
867	context.pixelStorei(GL_UNPACK_ALIGNMENT, 1);
868	createMetaballsTex2D(context, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
869
870	// Setup shaders
871	singleTexShader.setUnit(context, singleTexShaderID, 0);
872	mixShader.setUnits(context, mixShaderID, 0, 1);
873
874	// Fbo, quad with metaballs texture
875	Framebuffer fboA(context, getConfig(), m_fboAWidth, m_fboAHeight);
876	fboA.checkCompleteness();
877	context.bindFramebuffer(GL_FRAMEBUFFER, fboA.getFramebuffer());
878	context.viewport(0, 0, m_fboAWidth, m_fboAHeight);
879	context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
880	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
881	context.bindTexture(GL_TEXTURE_2D, metaballsTex);
882	sglr::drawQuad(context, singleTexShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
883
884	// Fbo, color clears
885	Framebuffer fboB(context, getConfig(), m_fboBWidth, m_fboBHeight);
886	fboB.checkCompleteness();
887	context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer());
888	context.viewport(0, 0, m_fboBWidth, m_fboBHeight);
889	context.enable(GL_SCISSOR_TEST);
890	context.scissor(0, 0, 32, 64);
891	context.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
892	context.clear(GL_COLOR_BUFFER_BIT);
893	context.scissor(32, 0, 32, 64);
894	context.clearColor(0.0f, 1.0f, 0.0f, 1.0f);
895	context.clear(GL_COLOR_BUFFER_BIT);
896	context.disable(GL_SCISSOR_TEST);
897
898	// Final mix op
899	context.activeTexture(GL_TEXTURE0);
900	context.bindTexture(GL_TEXTURE_2D, fboA.getColorbuffer());
901	context.activeTexture(GL_TEXTURE1);
902	context.bindTexture(GL_TEXTURE_2D, fboB.getColorbuffer());
903	context.bindFramebuffer(GL_FRAMEBUFFER, 0);
904	context.viewport(0, 0, context.getWidth(), context.getHeight());
905	sglr::drawQuad(context, mixShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
906
907	context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
908}
909
910class BlendTest : public FboRenderCase
911{
912public:
913						BlendTest			(Context& context, const FboConfig& config, bool npot = false);
914	virtual				~BlendTest			(void) {}
915
916	void				render				(sglr::Context& context, Surface& dst);
917
918	static bool			isConfigSupported	(const FboConfig& config);
919
920private:
921	int					m_fboWidth;
922	int					m_fboHeight;
923};
924
925class BlendNpotTest : public BlendTest
926{
927public:
928	BlendNpotTest (Context& context, const FboConfig& config)
929		: BlendTest(context, config, true)
930	{
931	}
932};
933
934BlendTest::BlendTest (Context& context, const FboConfig& config, bool npot)
935	: FboRenderCase	(context, (string(npot ? "blend_npot_" : "blend_") + config.getName()).c_str(), "Blend to fbo", config)
936	, m_fboWidth	(npot ? 111 : 128)
937	, m_fboHeight	(npot ? 122 : 128)
938{
939}
940
941bool BlendTest::isConfigSupported (const FboConfig& config)
942{
943	// \note Disabled for stencil configurations since doesn't exercise stencil buffer
944	return config.stencilbufferType	== GL_NONE;
945}
946
947void BlendTest::render (sglr::Context& context, Surface& dst)
948{
949	SingleTex2DShader	shader;
950	deUint32			shaderID		= context.createProgram(&shader);
951	int					width			= m_fboWidth;
952	int					height			= m_fboHeight;
953	deUint32			metaballsTex	= 1;
954
955	createMetaballsTex2D(context, metaballsTex, GL_RGBA, GL_UNSIGNED_BYTE, 64, 64);
956
957	Framebuffer fbo(context, getConfig(), width, height);
958	fbo.checkCompleteness();
959
960	shader.setUnit(context, shaderID, 0);
961
962	context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
963	context.viewport(0, 0, width, height);
964	context.bindTexture(GL_TEXTURE_2D, metaballsTex);
965	context.clearColor(0.6f, 0.0f, 0.6f, 1.0f);
966	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
967
968	context.enable(GL_BLEND);
969	context.blendEquation(GL_FUNC_ADD);
970	context.blendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
971	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
972	context.disable(GL_BLEND);
973
974	if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D)
975	{
976		context.bindFramebuffer(GL_FRAMEBUFFER, 0);
977		context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
978		context.viewport(0, 0, context.getWidth(), context.getHeight());
979		sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
980		context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
981	}
982	else
983		context.readPixels(dst, 0, 0, width, height);
984}
985
986class StencilClearsTest : public FboRenderCase
987{
988public:
989						StencilClearsTest		(Context& context, const FboConfig& config);
990	virtual				~StencilClearsTest		(void) {};
991
992	void				render					(sglr::Context& context, Surface& dst);
993
994	static bool			isConfigSupported		(const FboConfig& config);
995};
996
997StencilClearsTest::StencilClearsTest (Context& context, const FboConfig& config)
998	: FboRenderCase(context, config.getName().c_str(), "Stencil clears", config)
999{
1000}
1001
1002void StencilClearsTest::render (sglr::Context& context, Surface& dst)
1003{
1004	SingleTex2DShader	shader;
1005	deUint32			shaderID		= context.createProgram(&shader);
1006	int					width			= 128;
1007	int					height			= 128;
1008	deUint32			quadsTex		= 1;
1009	deUint32			metaballsTex	= 2;
1010
1011	createQuadsTex2D(context, quadsTex, GL_RGBA, GL_UNSIGNED_BYTE, width, height);
1012	createMetaballsTex2D(context, metaballsTex, GL_RGBA, GL_UNSIGNED_BYTE, width, height);
1013
1014	Framebuffer fbo(context, getConfig(), width, height);
1015	fbo.checkCompleteness();
1016
1017	// Bind framebuffer and clear
1018	context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1019	context.viewport(0, 0, width, height);
1020	context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1021	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1022
1023	// Do stencil clears
1024	context.enable(GL_SCISSOR_TEST);
1025	context.scissor(10, 16, 32, 120);
1026	context.clearStencil(1);
1027	context.clear(GL_STENCIL_BUFFER_BIT);
1028	context.scissor(16, 32, 100, 64);
1029	context.clearStencil(2);
1030	context.clear(GL_STENCIL_BUFFER_BIT);
1031	context.disable(GL_SCISSOR_TEST);
1032
1033	// Draw 2 textures with stecil tests
1034	context.activeTexture(GL_TEXTURE0);
1035	context.bindTexture(GL_TEXTURE_2D, quadsTex);
1036	context.activeTexture(GL_TEXTURE1);
1037	context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1038
1039	context.enable(GL_STENCIL_TEST);
1040	context.stencilFunc(GL_EQUAL, 1, 0xffffffffu);
1041	shader.setUnit(context, shaderID, 0);
1042	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1043
1044	context.stencilFunc(GL_EQUAL, 2, 0xffffffffu);
1045	shader.setUnit(context, shaderID, 1);
1046	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1047
1048	context.disable(GL_STENCIL_TEST);
1049
1050	if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D)
1051	{
1052		context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1053		context.activeTexture(GL_TEXTURE0);
1054		context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
1055		context.viewport(0, 0, context.getWidth(), context.getHeight());
1056		shader.setUnit(context, shaderID, 0);
1057		sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1058		context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1059	}
1060	else
1061		context.readPixels(dst, 0, 0, width, height);
1062}
1063
1064bool StencilClearsTest::isConfigSupported (const FboConfig& config)
1065{
1066	return config.stencilbufferType != GL_NONE;
1067}
1068
1069class StencilTest : public FboRenderCase
1070{
1071public:
1072						StencilTest				(Context& context, const FboConfig& config, bool npot = false);
1073	virtual				~StencilTest			(void) {};
1074
1075	void				render					(sglr::Context& context, Surface& dst);
1076
1077	static bool			isConfigSupported		(const FboConfig& config);
1078
1079private:
1080	int					m_fboWidth;
1081	int					m_fboHeight;
1082};
1083
1084class StencilNpotTest : public StencilTest
1085{
1086public:
1087	StencilNpotTest (Context& context, const FboConfig& config)
1088		: StencilTest(context, config, true)
1089	{
1090	}
1091};
1092
1093StencilTest::StencilTest (Context& context, const FboConfig& config, bool npot)
1094	: FboRenderCase	(context, (string(npot ? "npot_" : "") + config.getName()).c_str(), "Stencil ops", config)
1095	, m_fboWidth	(npot ?  99 : 128)
1096	, m_fboHeight	(npot ? 110 : 128)
1097{
1098}
1099
1100bool StencilTest::isConfigSupported (const FboConfig& config)
1101{
1102	return config.stencilbufferType != GL_NONE;
1103}
1104
1105void StencilTest::render (sglr::Context& ctx, Surface& dst)
1106{
1107	FlatColorShader		colorShader;
1108	SingleTex2DShader	texShader;
1109	deUint32			colorShaderID	= ctx.createProgram(&colorShader);
1110	deUint32			texShaderID		= ctx.createProgram(&texShader);
1111	int					width			= m_fboWidth;
1112	int					height			= m_fboHeight;
1113	int					texWidth		= 64;
1114	int					texHeight		= 64;
1115	deUint32			quadsTex		= 1;
1116	deUint32			metaballsTex	= 2;
1117	bool				depth			= getConfig().depthbufferType != GL_NONE;
1118
1119	createQuadsTex2D(ctx, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight);
1120	createMetaballsTex2D(ctx, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight);
1121
1122	Framebuffer fbo(ctx, getConfig(), width, height);
1123	fbo.checkCompleteness();
1124
1125	// Bind framebuffer and clear
1126	ctx.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1127	ctx.viewport(0, 0, width, height);
1128	ctx.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1129	ctx.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1130
1131	// Render intersecting quads - increment stencil on depth pass
1132	ctx.enable(GL_DEPTH_TEST);
1133	ctx.enable(GL_STENCIL_TEST);
1134	ctx.stencilFunc(GL_ALWAYS, 0, 0xffu);
1135	ctx.stencilOp(GL_KEEP, GL_KEEP, GL_INCR);
1136
1137	colorShader.setColor(ctx, colorShaderID, Vec4(0.0f, 0.0f, 1.0f, 1.0f));
1138	sglr::drawQuad(ctx, colorShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
1139
1140	ctx.bindTexture(GL_TEXTURE_2D, quadsTex);
1141	texShader.setUnit(ctx, texShaderID, 0);
1142	sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(+1.0f, +1.0f, +1.0f));
1143
1144	// Draw quad with stencil test (stencil == 1 or 2 depending on depth) - decrement on stencil failure
1145	ctx.disable(GL_DEPTH_TEST);
1146	ctx.stencilFunc(GL_EQUAL, depth ? 2 : 1, 0xffu);
1147	ctx.stencilOp(GL_DECR, GL_KEEP, GL_KEEP);
1148	colorShader.setColor(ctx, colorShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1149	sglr::drawQuad(ctx, colorShaderID, Vec3(-0.5f, -0.5f, 0.0f), Vec3(+0.5f, +0.5f, 0.0f));
1150
1151	// Draw metaballs with stencil test where stencil > 1 or 2 depending on depth buffer
1152	ctx.bindTexture(GL_TEXTURE_2D, metaballsTex);
1153	ctx.stencilFunc(GL_GREATER, depth ? 1 : 2, 0xffu);
1154	ctx.stencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1155	sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
1156
1157	ctx.disable(GL_STENCIL_TEST);
1158
1159	if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D)
1160	{
1161		ctx.bindFramebuffer(GL_FRAMEBUFFER, 0);
1162		ctx.activeTexture(GL_TEXTURE0);
1163		ctx.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
1164		ctx.viewport(0, 0, ctx.getWidth(), ctx.getHeight());
1165		sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1166		ctx.readPixels(dst, 0, 0, ctx.getWidth(), ctx.getHeight());
1167	}
1168	else
1169		ctx.readPixels(dst, 0, 0, width, height);
1170}
1171
1172class SharedColorbufferTest : public FboRenderCase
1173{
1174public:
1175						SharedColorbufferTest			(Context& context, const FboConfig& config);
1176	virtual				~SharedColorbufferTest			(void) {};
1177
1178	void				render							(sglr::Context& context, Surface& dst);
1179};
1180
1181SharedColorbufferTest::SharedColorbufferTest (Context& context, const FboConfig& config)
1182	: FboRenderCase(context, config.getName().c_str(), "Shared colorbuffer", config)
1183{
1184}
1185
1186void SharedColorbufferTest::render (sglr::Context& context, Surface& dst)
1187{
1188	SingleTex2DShader	shader;
1189	deUint32			shaderID		= context.createProgram(&shader);
1190	int					width			= 128;
1191	int					height			= 128;
1192//	bool				depth			= getConfig().depthbufferFormat		!= GL_NONE;
1193	bool				stencil			= getConfig().stencilbufferFormat	!= GL_NONE;
1194
1195	// Textures
1196	deUint32	quadsTex		= 1;
1197	deUint32	metaballsTex	= 2;
1198	createQuadsTex2D(context, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1199	createMetaballsTex2D(context, metaballsTex, GL_RGBA, GL_UNSIGNED_BYTE, 64, 64);
1200
1201	context.viewport(0, 0, width, height);
1202
1203	shader.setUnit(context, shaderID, 0);
1204
1205	// Fbo A
1206	Framebuffer fboA(context, getConfig(), width, height);
1207	fboA.checkCompleteness();
1208
1209	// Fbo B - don't create colorbuffer
1210	FboConfig cfg = getConfig();
1211	cfg.colorbufferType		= GL_NONE;
1212	cfg.colorbufferFormat	= GL_NONE;
1213	Framebuffer fboB(context, cfg, width, height);
1214
1215	// Attach color buffer from fbo A
1216	context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer());
1217	switch (getConfig().colorbufferType)
1218	{
1219		case GL_TEXTURE_2D:
1220			context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboA.getColorbuffer(), 0);
1221			break;
1222
1223		case GL_RENDERBUFFER:
1224			context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fboA.getColorbuffer());
1225			break;
1226
1227		default:
1228			DE_ASSERT(false);
1229	}
1230
1231	// Clear depth and stencil in fbo B
1232	context.clear(GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1233
1234	// Render quads to fbo 1, with depth 0.0
1235	context.bindFramebuffer(GL_FRAMEBUFFER, fboA.getFramebuffer());
1236	context.bindTexture(GL_TEXTURE_2D, quadsTex);
1237	context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1238	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1239
1240	if (stencil)
1241	{
1242		// Stencil to 1 in fbo A
1243		context.clearStencil(1);
1244		context.clear(GL_STENCIL_BUFFER_BIT);
1245	}
1246
1247	context.enable(GL_DEPTH_TEST);
1248	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1249	context.disable(GL_DEPTH_TEST);
1250
1251	// Blend metaballs to fbo 2
1252	context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer());
1253	context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1254	context.enable(GL_BLEND);
1255	context.blendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
1256	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1257
1258	// Render small quad that is only visible if depth buffer is not shared with fbo A - or there is no depth bits
1259	context.bindTexture(GL_TEXTURE_2D, quadsTex);
1260	context.enable(GL_DEPTH_TEST);
1261	sglr::drawQuad(context, shaderID, Vec3(0.5f, 0.5f, 0.5f), Vec3(1.0f, 1.0f, 0.5f));
1262	context.disable(GL_DEPTH_TEST);
1263
1264	if (stencil)
1265	{
1266		FlatColorShader flatShader;
1267		deUint32		flatShaderID = context.createProgram(&flatShader);
1268
1269		flatShader.setColor(context, flatShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1270
1271		// Clear subset of stencil buffer to 1
1272		context.enable(GL_SCISSOR_TEST);
1273		context.scissor(10, 10, 12, 25);
1274		context.clearStencil(1);
1275		context.clear(GL_STENCIL_BUFFER_BIT);
1276		context.disable(GL_SCISSOR_TEST);
1277
1278		// Render quad with stencil mask == 1
1279		context.enable(GL_STENCIL_TEST);
1280		context.stencilFunc(GL_EQUAL, 1, 0xffu);
1281		sglr::drawQuad(context, flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1282		context.disable(GL_STENCIL_TEST);
1283	}
1284
1285	// Get results
1286	if (fboA.getConfig().colorbufferType == GL_TEXTURE_2D)
1287	{
1288		context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1289		context.bindTexture(GL_TEXTURE_2D, fboA.getColorbuffer());
1290		context.viewport(0, 0, context.getWidth(), context.getHeight());
1291		sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1292		context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1293	}
1294	else
1295		context.readPixels(dst, 0, 0, width, height);
1296}
1297
1298class SharedColorbufferClearsTest : public FboRenderCase
1299{
1300public:
1301					SharedColorbufferClearsTest		(Context& context, const FboConfig& config);
1302	virtual			~SharedColorbufferClearsTest	(void) {}
1303
1304	static bool		isConfigSupported				(const FboConfig& config);
1305	void			render							(sglr::Context& context, Surface& dst);
1306};
1307
1308SharedColorbufferClearsTest::SharedColorbufferClearsTest (Context& context, const FboConfig& config)
1309	: FboRenderCase(context, config.getName().c_str(), "Shared colorbuffer clears", config)
1310{
1311}
1312
1313bool SharedColorbufferClearsTest::isConfigSupported (const FboConfig& config)
1314{
1315	return config.colorbufferType	!= GL_NONE &&
1316		   config.depthbufferType	== GL_NONE &&
1317		   config.stencilbufferType	== GL_NONE;
1318}
1319
1320void SharedColorbufferClearsTest::render (sglr::Context& context, Surface& dst)
1321{
1322	int			width			= 128;
1323	int			height			= 128;
1324	deUint32	colorbuffer		= 1;
1325
1326	checkColorFormatSupport(context, getConfig().colorbufferFormat);
1327
1328	// Single colorbuffer
1329	if (getConfig().colorbufferType == GL_TEXTURE_2D)
1330	{
1331		context.bindTexture(GL_TEXTURE_2D, colorbuffer);
1332		context.texImage2D(GL_TEXTURE_2D, 0, getConfig().colorbufferFormat, width, height);
1333		context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1334	}
1335	else
1336	{
1337		DE_ASSERT(getConfig().colorbufferType == GL_RENDERBUFFER);
1338		context.bindRenderbuffer(GL_RENDERBUFFER, colorbuffer);
1339		context.renderbufferStorage(GL_RENDERBUFFER, getConfig().colorbufferFormat, width, height);
1340	}
1341
1342	// Multiple framebuffers sharing the colorbuffer
1343	for (int fbo = 1; fbo <= 3; fbo++)
1344	{
1345		context.bindFramebuffer(GL_FRAMEBUFFER, fbo);
1346
1347		if (getConfig().colorbufferType == GL_TEXTURE_2D)
1348			context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0);
1349		else
1350			context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer);
1351	}
1352
1353	context.bindFramebuffer(GL_FRAMEBUFFER, 1);
1354
1355	// Check completeness
1356	{
1357		GLenum status = context.checkFramebufferStatus(GL_FRAMEBUFFER);
1358		if (status != GL_FRAMEBUFFER_COMPLETE)
1359			throw FboIncompleteException(getConfig(), status, __FILE__, __LINE__);
1360	}
1361
1362	// Render to them
1363	context.viewport(0, 0, width, height);
1364	context.clearColor(0.0f, 0.0f, 1.0f, 1.0f);
1365	context.clear(GL_COLOR_BUFFER_BIT);
1366
1367	context.enable(GL_SCISSOR_TEST);
1368
1369	context.bindFramebuffer(GL_FRAMEBUFFER, 2);
1370	context.clearColor(0.6f, 0.0f, 0.0f, 1.0f);
1371	context.scissor(10, 10, 64, 64);
1372	context.clear(GL_COLOR_BUFFER_BIT);
1373	context.clearColor(0.0f, 0.6f, 0.0f, 1.0f);
1374	context.scissor(60, 60, 40, 20);
1375	context.clear(GL_COLOR_BUFFER_BIT);
1376
1377	context.bindFramebuffer(GL_FRAMEBUFFER, 3);
1378	context.clearColor(0.0f, 0.0f, 0.6f, 1.0f);
1379	context.scissor(20, 20, 100, 10);
1380	context.clear(GL_COLOR_BUFFER_BIT);
1381
1382	context.bindFramebuffer(GL_FRAMEBUFFER, 1);
1383	context.clearColor(0.6f, 0.0f, 0.6f, 1.0f);
1384	context.scissor(20, 20, 5, 100);
1385	context.clear(GL_COLOR_BUFFER_BIT);
1386
1387	context.disable(GL_SCISSOR_TEST);
1388
1389	if (getConfig().colorbufferType == GL_TEXTURE_2D)
1390	{
1391		SingleTex2DShader	shader;
1392		deUint32			shaderID = context.createProgram(&shader);
1393
1394		shader.setUnit(context, shaderID, 0);
1395
1396		context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1397		context.viewport(0, 0, context.getWidth(), context.getHeight());
1398		sglr::drawQuad(context, shaderID, Vec3(-0.9f, -0.9f, 0.0f), Vec3(0.9f, 0.9f, 0.0f));
1399		context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1400	}
1401	else
1402		context.readPixels(dst, 0, 0, width, height);
1403}
1404
1405class SharedDepthbufferTest : public FboRenderCase
1406{
1407public:
1408					SharedDepthbufferTest		(Context& context, const FboConfig& config);
1409	virtual			~SharedDepthbufferTest		(void) {};
1410
1411	static bool		isConfigSupported			(const FboConfig& config);
1412	void			render						(sglr::Context& context, Surface& dst);
1413};
1414
1415SharedDepthbufferTest::SharedDepthbufferTest (Context& context, const FboConfig& config)
1416	: FboRenderCase(context, config.getName().c_str(), "Shared depthbuffer", config)
1417{
1418}
1419
1420bool SharedDepthbufferTest::isConfigSupported (const FboConfig& config)
1421{
1422	return config.depthbufferType == GL_RENDERBUFFER;
1423}
1424
1425void SharedDepthbufferTest::render (sglr::Context& context, Surface& dst)
1426{
1427	SingleTex2DShader	texShader;
1428	FlatColorShader		colorShader;
1429	deUint32			texShaderID		= context.createProgram(&texShader);
1430	deUint32			colorShaderID	= context.createProgram(&colorShader);
1431	int					width			= 128;
1432	int					height			= 128;
1433	bool				stencil			= getConfig().stencilbufferType != GL_NONE;
1434
1435	// Setup shaders
1436	texShader.setUnit(context, texShaderID, 0);
1437	colorShader.setColor(context, colorShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1438
1439	// Textures
1440	deUint32 metaballsTex	= 5;
1441	deUint32 quadsTex		= 6;
1442	createMetaballsTex2D(context, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1443	createQuadsTex2D(context, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1444
1445	context.viewport(0, 0, width, height);
1446
1447	// Fbo A
1448	Framebuffer fboA(context, getConfig(), width, height);
1449	fboA.checkCompleteness();
1450
1451	// Fbo B
1452	FboConfig cfg = getConfig();
1453	cfg.depthbufferType		= GL_NONE;
1454	cfg.depthbufferFormat	= GL_NONE;
1455	Framebuffer fboB(context, cfg, width, height);
1456
1457	// Bind depth buffer from fbo A to fbo B
1458	DE_ASSERT(fboA.getConfig().depthbufferType == GL_RENDERBUFFER);
1459	context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer());
1460	context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fboA.getDepthbuffer());
1461
1462	// Clear fbo B color to red and stencil to 1
1463	context.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
1464	context.clearStencil(1);
1465	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1466
1467	// Enable depth test.
1468	context.enable(GL_DEPTH_TEST);
1469
1470	// Render quad to fbo A
1471	context.bindFramebuffer(GL_FRAMEBUFFER, fboA.getFramebuffer());
1472	context.bindTexture(GL_TEXTURE_2D, quadsTex);
1473	context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1474	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1475	sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1476
1477	// Render metaballs to fbo B
1478	context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer());
1479	context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1480	sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f));
1481
1482	context.disable(GL_DEPTH_TEST);
1483
1484	if (stencil)
1485	{
1486		// Clear subset of stencil buffer to 0
1487		context.enable(GL_SCISSOR_TEST);
1488		context.scissor(10, 10, 12, 25);
1489		context.clearStencil(0);
1490		context.clear(GL_STENCIL_BUFFER_BIT);
1491		context.disable(GL_SCISSOR_TEST);
1492
1493		// Render quad with stencil mask == 0
1494		context.enable(GL_STENCIL_TEST);
1495		context.stencilFunc(GL_EQUAL, 0, 0xffu);
1496		sglr::drawQuad(context, colorShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1497		context.disable(GL_STENCIL_TEST);
1498	}
1499
1500	if (getConfig().colorbufferType == GL_TEXTURE_2D)
1501	{
1502		// Render both to screen
1503		context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1504		context.viewport(0, 0, context.getWidth(), context.getHeight());
1505		context.bindTexture(GL_TEXTURE_2D, fboA.getColorbuffer());
1506		sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(0.0f, 1.0f, 0.0f));
1507		context.bindTexture(GL_TEXTURE_2D, fboB.getColorbuffer());
1508		sglr::drawQuad(context, texShaderID, Vec3(0.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1509
1510		context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1511	}
1512	else
1513	{
1514		// Read results from fbo B
1515		context.readPixels(dst, 0, 0, width, height);
1516	}
1517}
1518
1519class TexSubImageAfterRenderTest : public FboRenderCase
1520{
1521public:
1522					TexSubImageAfterRenderTest		(Context& context, const FboConfig& config);
1523	virtual			~TexSubImageAfterRenderTest		(void) {}
1524
1525	static bool		isConfigSupported				(const FboConfig& config);
1526	void			render							(sglr::Context& context, Surface& dst);
1527};
1528
1529TexSubImageAfterRenderTest::TexSubImageAfterRenderTest (Context& context, const FboConfig& config)
1530	: FboRenderCase(context, (string("after_render_") + config.getName()).c_str(), "TexSubImage after rendering to texture", config)
1531{
1532}
1533
1534bool TexSubImageAfterRenderTest::isConfigSupported (const FboConfig& config)
1535{
1536	return config.colorbufferType == GL_TEXTURE_2D &&
1537		   (config.colorbufferFormat == GL_RGB || config.colorbufferFormat == GL_RGBA) &&
1538		   config.depthbufferType == GL_NONE &&
1539		   config.stencilbufferType == GL_NONE;
1540}
1541
1542void TexSubImageAfterRenderTest::render (sglr::Context& context, Surface& dst)
1543{
1544	SingleTex2DShader	shader;
1545	deUint32			shaderID	= context.createProgram(&shader);
1546	bool				isRGBA		= getConfig().colorbufferFormat == GL_RGBA;
1547
1548	tcu::TextureLevel fourQuads(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), 64, 64);
1549	tcu::fillWithRGBAQuads(fourQuads.getAccess());
1550
1551	tcu::TextureLevel metaballs(tcu::TextureFormat(isRGBA ? tcu::TextureFormat::RGBA : tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), 64, 64);
1552	tcu::fillWithMetaballs(metaballs.getAccess(), 5, 3);
1553
1554	shader.setUnit(context, shaderID, 0);
1555
1556	deUint32 fourQuadsTex = 1;
1557	context.bindTexture(GL_TEXTURE_2D, fourQuadsTex);
1558	context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1559	context.texImage2D(GL_TEXTURE_2D, 0, GL_RGB, 64, 64, 0, GL_RGB, GL_UNSIGNED_BYTE, fourQuads.getAccess().getDataPtr());
1560
1561	context.bindFramebuffer(GL_FRAMEBUFFER, 1);
1562
1563	deUint32 fboTex = 2;
1564	context.bindTexture(GL_TEXTURE_2D, fboTex);
1565	context.texImage2D(GL_TEXTURE_2D, 0, isRGBA ? GL_RGBA : GL_RGB, 128, 128);
1566	context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1567	context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0);
1568
1569	// Render to fbo
1570	context.viewport(0, 0, 128, 128);
1571	context.bindTexture(GL_TEXTURE_2D, fourQuadsTex);
1572	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1573
1574	// Update texture using TexSubImage2D
1575	context.bindTexture(GL_TEXTURE_2D, fboTex);
1576	context.texSubImage2D(GL_TEXTURE_2D, 0, 32, 32, 64, 64, isRGBA ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, metaballs.getAccess().getDataPtr());
1577
1578	// Draw to screen
1579	context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1580	context.viewport(0, 0, context.getWidth(), context.getHeight());
1581	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1582	context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1583}
1584
1585class TexSubImageBetweenRenderTest : public FboRenderCase
1586{
1587public:
1588					TexSubImageBetweenRenderTest		(Context& context, const FboConfig& config);
1589	virtual			~TexSubImageBetweenRenderTest		(void) {}
1590
1591	static bool		isConfigSupported					(const FboConfig& config);
1592	void			render								(sglr::Context& context, Surface& dst);
1593};
1594
1595TexSubImageBetweenRenderTest::TexSubImageBetweenRenderTest (Context& context, const FboConfig& config)
1596	: FboRenderCase(context, (string("between_render_") + config.getName()).c_str(), "TexSubImage between rendering calls", config)
1597{
1598}
1599
1600bool TexSubImageBetweenRenderTest::isConfigSupported (const FboConfig& config)
1601{
1602	return config.colorbufferType == GL_TEXTURE_2D &&
1603		   (config.colorbufferFormat == GL_RGB || config.colorbufferFormat == GL_RGBA) &&
1604		   config.depthbufferType == GL_NONE &&
1605		   config.stencilbufferType == GL_NONE;
1606}
1607
1608void TexSubImageBetweenRenderTest::render (sglr::Context& context, Surface& dst)
1609{
1610	SingleTex2DShader	shader;
1611	deUint32			shaderID	= context.createProgram(&shader);
1612	bool				isRGBA		= getConfig().colorbufferFormat == GL_RGBA;
1613
1614	tcu::TextureLevel fourQuads(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), 64, 64);
1615	tcu::fillWithRGBAQuads(fourQuads.getAccess());
1616
1617	tcu::TextureLevel metaballs(tcu::TextureFormat(isRGBA ? tcu::TextureFormat::RGBA : tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), 64, 64);
1618	tcu::fillWithMetaballs(metaballs.getAccess(), 5, 3);
1619
1620	tcu::TextureLevel metaballs2(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 64, 64);
1621	tcu::fillWithMetaballs(metaballs2.getAccess(), 5, 4);
1622
1623	deUint32 metaballsTex = 3;
1624	context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1625	context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1626	context.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, metaballs2.getAccess().getDataPtr());
1627
1628	deUint32 fourQuadsTex = 1;
1629	context.bindTexture(GL_TEXTURE_2D, fourQuadsTex);
1630	context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1631	context.texImage2D(GL_TEXTURE_2D, 0, GL_RGB, 64, 64, 0, GL_RGB, GL_UNSIGNED_BYTE, fourQuads.getAccess().getDataPtr());
1632
1633	context.bindFramebuffer(GL_FRAMEBUFFER, 1);
1634
1635	deUint32 fboTex = 2;
1636	context.bindTexture(GL_TEXTURE_2D, fboTex);
1637	context.texImage2D(GL_TEXTURE_2D, 0, isRGBA ? GL_RGBA : GL_RGB, 128, 128);
1638	context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1639	context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0);
1640
1641	shader.setUnit(context, shaderID, 0);
1642
1643	// Render to fbo
1644	context.viewport(0, 0, 128, 128);
1645	context.bindTexture(GL_TEXTURE_2D, fourQuadsTex);
1646	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1647
1648	// Update texture using TexSubImage2D
1649	context.bindTexture(GL_TEXTURE_2D, fboTex);
1650	context.texSubImage2D(GL_TEXTURE_2D, 0, 32, 32, 64, 64, isRGBA ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, metaballs.getAccess().getDataPtr());
1651
1652	// Render again to fbo
1653	context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1654	context.enable(GL_BLEND);
1655	context.blendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
1656	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1657	context.disable(GL_BLEND);
1658
1659	// Draw to screen
1660	context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1661	context.viewport(0, 0, context.getWidth(), context.getHeight());
1662	context.bindTexture(GL_TEXTURE_2D, fboTex);
1663	sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1664
1665	context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1666}
1667
1668class ResizeTest : public FboRenderCase
1669{
1670public:
1671					ResizeTest				(Context& context, const FboConfig& config);
1672	virtual			~ResizeTest				(void) {}
1673
1674	void			render					(sglr::Context& context, Surface& dst);
1675};
1676
1677ResizeTest::ResizeTest (Context& context, const FboConfig& config)
1678	: FboRenderCase(context, config.getName().c_str(), "Resize framebuffer", config)
1679{
1680}
1681
1682void ResizeTest::render (sglr::Context& context, Surface& dst)
1683{
1684	SingleTex2DShader	texShader;
1685	FlatColorShader		colorShader;
1686	deUint32			texShaderID		= context.createProgram(&texShader);
1687	deUint32			colorShaderID	= context.createProgram(&colorShader);
1688	deUint32			quadsTex		= 1;
1689	deUint32			metaballsTex	= 2;
1690	bool				depth			= getConfig().depthbufferType	 != GL_NONE;
1691	bool				stencil			= getConfig().stencilbufferType	 != GL_NONE;
1692
1693	createQuadsTex2D(context, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1694	createMetaballsTex2D(context, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 32, 32);
1695
1696	Framebuffer fbo(context, getConfig(), 128, 128);
1697	fbo.checkCompleteness();
1698
1699	// Setup shaders
1700	texShader.setUnit(context, texShaderID, 0);
1701	colorShader.setColor(context, colorShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1702
1703	// Render quads
1704	context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1705	context.viewport(0, 0, 128, 128);
1706	context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1707	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1708	context.bindTexture(GL_TEXTURE_2D, quadsTex);
1709	sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1710
1711	if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D)
1712	{
1713		// Render fbo to screen
1714		context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1715		context.viewport(0, 0, context.getWidth(), context.getHeight());
1716		context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
1717		sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1718
1719		// Restore binding
1720		context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1721	}
1722
1723	int newWidth	= 64;
1724	int newHeight	= 32;
1725
1726	// Resize buffers
1727	switch (fbo.getConfig().colorbufferType)
1728	{
1729		case GL_TEXTURE_2D:
1730			context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
1731			context.texImage2D(GL_TEXTURE_2D, 0, fbo.getConfig().colorbufferFormat, newWidth, newHeight);
1732			break;
1733
1734		case GL_RENDERBUFFER:
1735			context.bindRenderbuffer(GL_RENDERBUFFER, fbo.getColorbuffer());
1736			context.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().colorbufferFormat, newWidth, newHeight);
1737			break;
1738
1739		default:
1740			DE_ASSERT(false);
1741	}
1742
1743	if (depth)
1744	{
1745		DE_ASSERT(fbo.getConfig().depthbufferType == GL_RENDERBUFFER);
1746		context.bindRenderbuffer(GL_RENDERBUFFER, fbo.getDepthbuffer());
1747		context.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().depthbufferFormat, newWidth, newHeight);
1748	}
1749
1750	if (stencil)
1751	{
1752		DE_ASSERT(fbo.getConfig().stencilbufferType == GL_RENDERBUFFER);
1753		context.bindRenderbuffer(GL_RENDERBUFFER, fbo.getStencilbuffer());
1754		context.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().stencilbufferFormat, newWidth, newHeight);
1755	}
1756
1757	// Render to resized fbo
1758	context.viewport(0, 0, newWidth, newHeight);
1759	context.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
1760	context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1761
1762	context.enable(GL_DEPTH_TEST);
1763
1764	context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1765	sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
1766
1767	context.bindTexture(GL_TEXTURE_2D, quadsTex);
1768	sglr::drawQuad(context, texShaderID, Vec3(0.0f, 0.0f, -1.0f), Vec3(+1.0f, +1.0f, 1.0f));
1769
1770	context.disable(GL_DEPTH_TEST);
1771
1772	if (stencil)
1773	{
1774		context.enable(GL_SCISSOR_TEST);
1775		context.scissor(10, 10, 5, 15);
1776		context.clearStencil(1);
1777		context.clear(GL_STENCIL_BUFFER_BIT);
1778		context.disable(GL_SCISSOR_TEST);
1779
1780		context.enable(GL_STENCIL_TEST);
1781		context.stencilFunc(GL_EQUAL, 1, 0xffu);
1782		sglr::drawQuad(context, colorShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
1783		context.disable(GL_STENCIL_TEST);
1784	}
1785
1786	if (getConfig().colorbufferType == GL_TEXTURE_2D)
1787	{
1788		context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1789		context.viewport(0, 0, context.getWidth(), context.getHeight());
1790		context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
1791		sglr::drawQuad(context, texShaderID, Vec3(-0.5f, -0.5f, 0.0f), Vec3(0.5f, 0.5f, 0.0f));
1792		context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1793	}
1794	else
1795		context.readPixels(dst, 0, 0, newWidth, newHeight);
1796}
1797
1798template <GLenum Buffers>
1799class RecreateBuffersTest : public FboRenderCase
1800{
1801public:
1802					RecreateBuffersTest			(Context& context, const FboConfig& config, bool rebind);
1803	virtual			~RecreateBuffersTest		(void) {}
1804
1805	static bool		isConfigSupported			(const FboConfig& config);
1806	void			render						(sglr::Context& context, Surface& dst);
1807
1808private:
1809	bool			m_rebind;
1810};
1811
1812template <GLenum Buffers>
1813class RecreateBuffersNoRebindTest : public RecreateBuffersTest<Buffers>
1814{
1815public:
1816	RecreateBuffersNoRebindTest (Context& context, const FboConfig& config)
1817		: RecreateBuffersTest<Buffers>(context, config, false)
1818	{
1819	}
1820};
1821
1822template <GLenum Buffers>
1823class RecreateBuffersRebindTest : public RecreateBuffersTest<Buffers>
1824{
1825public:
1826	RecreateBuffersRebindTest (Context& context, const FboConfig& config)
1827		: RecreateBuffersTest<Buffers>(context, config, true)
1828	{
1829	}
1830};
1831
1832template <GLenum Buffers>
1833RecreateBuffersTest<Buffers>::RecreateBuffersTest (Context& context, const FboConfig& config, bool rebind)
1834	: FboRenderCase		(context, (string(rebind ? "rebind_" : "no_rebind_") + config.getName()).c_str(), "Recreate buffers", config)
1835	, m_rebind			(rebind)
1836{
1837}
1838
1839template <GLenum Buffers>
1840bool RecreateBuffersTest<Buffers>::isConfigSupported (const FboConfig& config)
1841{
1842	if ((Buffers & GL_COLOR_BUFFER_BIT) && config.colorbufferType == GL_NONE)
1843		return false;
1844	if ((Buffers & GL_DEPTH_BUFFER_BIT) && config.depthbufferType == GL_NONE)
1845		return false;
1846	if ((Buffers & GL_STENCIL_BUFFER_BIT) && config.stencilbufferType == GL_NONE)
1847		return false;
1848	return true;
1849}
1850
1851template <GLenum Buffers>
1852void RecreateBuffersTest<Buffers>::render (sglr::Context& ctx, Surface& dst)
1853{
1854	SingleTex2DShader	texShader;
1855	deUint32			texShaderID		= ctx.createProgram(&texShader);
1856	int					width			= 128;
1857	int					height			= 128;
1858	deUint32			metaballsTex	= 1;
1859	deUint32			quadsTex		= 2;
1860	bool				stencil			= getConfig().stencilbufferType != GL_NONE;
1861
1862	createQuadsTex2D(ctx, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1863	createMetaballsTex2D(ctx, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1864
1865	Framebuffer fbo(ctx, getConfig(), width, height);
1866	fbo.checkCompleteness();
1867
1868	// Setup shader
1869	texShader.setUnit(ctx, texShaderID, 0);
1870
1871	// Draw scene
1872	ctx.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1873	ctx.viewport(0, 0, width, height);
1874	ctx.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
1875	ctx.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1876
1877	ctx.enable(GL_DEPTH_TEST);
1878
1879	ctx.bindTexture(GL_TEXTURE_2D, quadsTex);
1880	sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1881
1882	if (stencil)
1883	{
1884		ctx.enable(GL_SCISSOR_TEST);
1885		ctx.scissor(width/4, height/4, width/2, height/2);
1886		ctx.clearStencil(1);
1887		ctx.clear(GL_STENCIL_BUFFER_BIT);
1888		ctx.disable(GL_SCISSOR_TEST);
1889	}
1890
1891	// Recreate buffers
1892	if (!m_rebind)
1893		ctx.bindFramebuffer(GL_FRAMEBUFFER, 0);
1894
1895	if (Buffers & GL_COLOR_BUFFER_BIT)
1896	{
1897		deUint32 colorbuf = fbo.getColorbuffer();
1898		switch (fbo.getConfig().colorbufferType)
1899		{
1900			case GL_TEXTURE_2D:
1901				ctx.deleteTextures(1, &colorbuf);
1902				ctx.bindTexture(GL_TEXTURE_2D, colorbuf);
1903				ctx.texImage2D(GL_TEXTURE_2D, 0, fbo.getConfig().colorbufferFormat, width, height);
1904				ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1905
1906				if (m_rebind)
1907					ctx.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuf, 0);
1908				break;
1909
1910			case GL_RENDERBUFFER:
1911				ctx.deleteRenderbuffers(1, &colorbuf);
1912				ctx.bindRenderbuffer(GL_RENDERBUFFER, colorbuf);
1913				ctx.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().colorbufferFormat, width, height);
1914
1915				if (m_rebind)
1916					ctx.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuf);
1917				break;
1918
1919			default:
1920				DE_ASSERT(false);
1921		}
1922	}
1923
1924	if (Buffers & GL_DEPTH_BUFFER_BIT)
1925	{
1926		deUint32 depthbuf = fbo.getDepthbuffer();
1927		DE_ASSERT(fbo.getConfig().depthbufferType == GL_RENDERBUFFER);
1928
1929		ctx.deleteRenderbuffers(1, &depthbuf);
1930		ctx.bindRenderbuffer(GL_RENDERBUFFER, depthbuf);
1931		ctx.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().depthbufferFormat, width, height);
1932
1933		if (m_rebind)
1934			ctx.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthbuf);
1935	}
1936
1937	if (Buffers & GL_STENCIL_BUFFER_BIT)
1938	{
1939		deUint32 stencilbuf = fbo.getStencilbuffer();
1940		DE_ASSERT(fbo.getConfig().stencilbufferType == GL_RENDERBUFFER);
1941
1942		ctx.deleteRenderbuffers(1, &stencilbuf);
1943		ctx.bindRenderbuffer(GL_RENDERBUFFER, stencilbuf);
1944		ctx.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().stencilbufferFormat, width, height);
1945
1946		if (m_rebind)
1947			ctx.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencilbuf);
1948	}
1949
1950	if (!m_rebind)
1951		ctx.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1952
1953	ctx.clearColor(0.0f, 0.0f, 1.0f, 0.0f);
1954	ctx.clearStencil(0);
1955	ctx.clear(Buffers); // \note Clear only buffers that were re-created
1956
1957	if (stencil)
1958	{
1959		// \note Stencil test enabled only if we have stencil buffer
1960		ctx.enable(GL_STENCIL_TEST);
1961		ctx.stencilFunc(GL_EQUAL, 0, 0xffu);
1962	}
1963	ctx.bindTexture(GL_TEXTURE_2D, metaballsTex);
1964	sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 1.0f), Vec3(1.0f, 1.0f, -1.0f));
1965	if (stencil)
1966		ctx.disable(GL_STENCIL_TEST);
1967
1968	ctx.disable(GL_DEPTH_TEST);
1969
1970	// Read from fbo
1971	ctx.readPixels(dst, 0, 0, width, height);
1972}
1973
1974class RepeatedClearCase : public FboRenderCase
1975{
1976private:
1977	static FboConfig makeConfig (deUint32 format)
1978	{
1979		FboConfig cfg;
1980		cfg.colorbufferType		= GL_TEXTURE_2D;
1981		cfg.colorbufferFormat	= format;
1982		cfg.depthbufferType		= GL_NONE;
1983		cfg.stencilbufferType	= GL_NONE;
1984		return cfg;
1985	}
1986
1987public:
1988	RepeatedClearCase (Context& context, deUint32 format)
1989		: FboRenderCase(context, makeConfig(format).getName().c_str(), "Repeated clears", makeConfig(format))
1990	{
1991	}
1992
1993protected:
1994	void render (sglr::Context& ctx, Surface& dst)
1995	{
1996		const int						numRowsCols		= 4;
1997		const int						cellSize		= 16;
1998		const int						fboSizes[]		= { cellSize, cellSize*numRowsCols };
1999
2000		SingleTex2DShader				fboBlitShader;
2001		const deUint32					fboBlitShaderID	= ctx.createProgram(&fboBlitShader);
2002
2003		de::Random						rnd				(18169662);
2004		deUint32						fbos[]			= { 0, 0 };
2005		deUint32						textures[]		= { 0, 0 };
2006
2007		ctx.genFramebuffers(2, &fbos[0]);
2008		ctx.genTextures(2, &textures[0]);
2009
2010		for (int fboNdx = 0; fboNdx < DE_LENGTH_OF_ARRAY(fbos); fboNdx++)
2011		{
2012			ctx.bindTexture(GL_TEXTURE_2D, textures[fboNdx]);
2013			ctx.texImage2D(GL_TEXTURE_2D, 0, getConfig().colorbufferFormat, fboSizes[fboNdx], fboSizes[fboNdx], 0,
2014						   getConfig().colorbufferFormat, GL_UNSIGNED_BYTE, DE_NULL);
2015			ctx.texParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
2016			ctx.texParameteri(GL_TEXTURE_2D,	GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
2017			ctx.texParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MIN_FILTER,	GL_NEAREST);
2018			ctx.texParameteri(GL_TEXTURE_2D,	GL_TEXTURE_MAG_FILTER,	GL_NEAREST);
2019
2020			ctx.bindFramebuffer(GL_FRAMEBUFFER, fbos[fboNdx]);
2021			ctx.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[fboNdx], 0);
2022
2023			{
2024				const GLenum status = ctx.checkFramebufferStatus(GL_FRAMEBUFFER);
2025				if (status != GL_FRAMEBUFFER_COMPLETE)
2026					throw FboIncompleteException(getConfig(), status, __FILE__, __LINE__);
2027			}
2028		}
2029
2030		// larger fbo bound -- clear to transparent black
2031		ctx.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
2032		ctx.clear(GL_COLOR_BUFFER_BIT);
2033
2034		fboBlitShader.setUnit(ctx, fboBlitShaderID, 0);
2035		ctx.bindTexture(GL_TEXTURE_2D, textures[0]);
2036
2037		for (int cellY = 0; cellY < numRowsCols; cellY++)
2038		for (int cellX = 0; cellX < numRowsCols; cellX++)
2039		{
2040			const float	r	= rnd.getFloat();
2041			const float	g	= rnd.getFloat();
2042			const float	b	= rnd.getFloat();
2043			const float	a	= rnd.getFloat();
2044
2045			ctx.bindFramebuffer(GL_FRAMEBUFFER, fbos[0]);
2046			ctx.clearColor(r, g, b, a);
2047			ctx.clear(GL_COLOR_BUFFER_BIT);
2048
2049			ctx.bindFramebuffer(GL_FRAMEBUFFER, fbos[1]);
2050			ctx.viewport(cellX*cellSize, cellY*cellSize, cellSize, cellSize);
2051			sglr::drawQuad(ctx, fboBlitShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
2052		}
2053
2054		ctx.readPixels(dst, 0, 0, fboSizes[1], fboSizes[1]);
2055	}
2056};
2057
2058} // FboCases
2059
2060FboRenderTestGroup::FboRenderTestGroup (Context& context)
2061	: TestCaseGroup(context, "render", "Rendering Tests")
2062{
2063}
2064
2065FboRenderTestGroup::~FboRenderTestGroup (void)
2066{
2067}
2068
2069namespace
2070{
2071
2072struct TypeFormatPair
2073{
2074	GLenum		type;
2075	GLenum		format;
2076};
2077
2078template <typename CaseType>
2079void addChildVariants (deqp::gles2::TestCaseGroup* group)
2080{
2081	TypeFormatPair colorbufferConfigs[] =
2082	{
2083//		{ GL_TEXTURE_2D,	GL_ALPHA },
2084//		{ GL_TEXTURE_2D,	GL_LUMINANCE },
2085//		{ GL_TEXTURE_2D,	GL_LUMINANCE_ALPHA },
2086		{ GL_TEXTURE_2D,	GL_RGB },
2087		{ GL_TEXTURE_2D,	GL_RGBA },
2088		{ GL_RENDERBUFFER,	GL_RGB565 },
2089		{ GL_RENDERBUFFER,	GL_RGB5_A1 },
2090		{ GL_RENDERBUFFER,	GL_RGBA4 },
2091//		{ GL_RENDERBUFFER,	GL_RGBA16F },
2092//		{ GL_RENDERBUFFER,	GL_RGB16F }
2093	};
2094	TypeFormatPair depthbufferConfigs[] =
2095	{
2096		{ GL_NONE,			GL_NONE },
2097		{ GL_RENDERBUFFER,	GL_DEPTH_COMPONENT16 }
2098	};
2099	TypeFormatPair stencilbufferConfigs[] =
2100	{
2101		{ GL_NONE,			GL_NONE },
2102		{ GL_RENDERBUFFER,	GL_STENCIL_INDEX8 }
2103	};
2104
2105	for (int colorbufferNdx = 0; colorbufferNdx < DE_LENGTH_OF_ARRAY(colorbufferConfigs); colorbufferNdx++)
2106	for (int depthbufferNdx = 0; depthbufferNdx < DE_LENGTH_OF_ARRAY(depthbufferConfigs); depthbufferNdx++)
2107	for (int stencilbufferNdx = 0; stencilbufferNdx < DE_LENGTH_OF_ARRAY(stencilbufferConfigs); stencilbufferNdx++)
2108	{
2109		FboConfig config;
2110		config.colorbufferType		= colorbufferConfigs[colorbufferNdx].type;
2111		config.colorbufferFormat	= colorbufferConfigs[colorbufferNdx].format;
2112		config.depthbufferType		= depthbufferConfigs[depthbufferNdx].type;
2113		config.depthbufferFormat	= depthbufferConfigs[depthbufferNdx].format;
2114		config.stencilbufferType	= stencilbufferConfigs[stencilbufferNdx].type;
2115		config.stencilbufferFormat	= stencilbufferConfigs[stencilbufferNdx].format;
2116
2117		if (CaseType::isConfigSupported(config))
2118			group->addChild(new CaseType(group->getContext(), config));
2119	}
2120}
2121
2122template <typename CaseType>
2123void createChildGroup (deqp::gles2::TestCaseGroup* parent, const char* name, const char* description)
2124{
2125	deqp::gles2::TestCaseGroup* tmpGroup = new deqp::gles2::TestCaseGroup(parent->getContext(), name, description);
2126	parent->addChild(tmpGroup);
2127	addChildVariants<CaseType>(tmpGroup);
2128}
2129
2130template <GLbitfield Buffers>
2131void createRecreateBuffersGroup (deqp::gles2::TestCaseGroup* parent, const char* name, const char* description)
2132{
2133	deqp::gles2::TestCaseGroup* tmpGroup = new deqp::gles2::TestCaseGroup(parent->getContext(), name, description);
2134	parent->addChild(tmpGroup);
2135	addChildVariants<FboCases::RecreateBuffersRebindTest<Buffers> >		(tmpGroup);
2136	addChildVariants<FboCases::RecreateBuffersNoRebindTest<Buffers> >	(tmpGroup);
2137}
2138
2139} // anonymous
2140
2141void FboRenderTestGroup::init (void)
2142{
2143	createChildGroup<FboCases::ColorClearsTest>					(this, "color_clear",		"Color buffer clears");
2144	createChildGroup<FboCases::StencilClearsTest>				(this, "stencil_clear",		"Stencil buffer clears");
2145
2146	deqp::gles2::TestCaseGroup* colorGroup = new deqp::gles2::TestCaseGroup(m_context, "color", "Color buffer tests");
2147	addChild(colorGroup);
2148	addChildVariants<FboCases::MixTest>			(colorGroup);
2149	addChildVariants<FboCases::MixNpotTest>		(colorGroup);
2150	addChildVariants<FboCases::BlendTest>		(colorGroup);
2151	addChildVariants<FboCases::BlendNpotTest>	(colorGroup);
2152
2153	deqp::gles2::TestCaseGroup* depthGroup = new deqp::gles2::TestCaseGroup(m_context, "depth", "Depth bufer tests");
2154	addChild(depthGroup);
2155	addChildVariants<FboCases::IntersectingQuadsTest>		(depthGroup);
2156	addChildVariants<FboCases::IntersectingQuadsNpotTest>	(depthGroup);
2157
2158	deqp::gles2::TestCaseGroup* stencilGroup = new deqp::gles2::TestCaseGroup(m_context, "stencil", "Stencil buffer tests");
2159	addChild(stencilGroup);
2160	addChildVariants<FboCases::StencilTest>		(stencilGroup);
2161	addChildVariants<FboCases::StencilNpotTest>	(stencilGroup);
2162
2163	createChildGroup<FboCases::SharedColorbufferClearsTest>		(this, "shared_colorbuffer_clear",	"Shared colorbuffer clears");
2164	createChildGroup<FboCases::SharedColorbufferTest>			(this, "shared_colorbuffer",		"Shared colorbuffer tests");
2165	createChildGroup<FboCases::SharedDepthbufferTest>			(this, "shared_depthbuffer",		"Shared depthbuffer tests");
2166	createChildGroup<FboCases::ResizeTest>						(this, "resize",					"FBO resize tests");
2167
2168	createRecreateBuffersGroup<GL_COLOR_BUFFER_BIT>				(this, "recreate_colorbuffer",		"Recreate colorbuffer tests");
2169	createRecreateBuffersGroup<GL_DEPTH_BUFFER_BIT>				(this, "recreate_depthbuffer",		"Recreate depthbuffer tests");
2170	createRecreateBuffersGroup<GL_STENCIL_BUFFER_BIT>			(this, "recreate_stencilbuffer",	"Recreate stencilbuffer tests");
2171
2172	deqp::gles2::TestCaseGroup* texSubImageGroup = new deqp::gles2::TestCaseGroup(m_context, "texsubimage", "TexSubImage interop with FBO colorbuffer texture");
2173	addChild(texSubImageGroup);
2174	addChildVariants<FboCases::TexSubImageAfterRenderTest>		(texSubImageGroup);
2175	addChildVariants<FboCases::TexSubImageBetweenRenderTest>	(texSubImageGroup);
2176
2177	{
2178		tcu::TestCaseGroup* const repeatedClearGroup = new tcu::TestCaseGroup(m_testCtx, "repeated_clear", "Repeated FBO clears");
2179		addChild(repeatedClearGroup);
2180
2181		repeatedClearGroup->addChild(new FboCases::RepeatedClearCase(m_context, GL_RGB));
2182		repeatedClearGroup->addChild(new FboCases::RepeatedClearCase(m_context, GL_RGBA));
2183	}
2184}
2185
2186} // Functional
2187} // gles2
2188} // deqp
2189