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 
46 using std::vector;
47 using std::string;
48 using tcu::Vec2;
49 using tcu::Vec3;
50 using tcu::Vec4;
51 using tcu::RGBA;
52 using tcu::Surface;
53 using namespace glw; // GL types
54 
55 namespace deqp
56 {
57 namespace gles2
58 {
59 namespace Functional
60 {
61 
62 // Shaders.
63 
64 class FlatColorShader : public sglr::ShaderProgram
65 {
66 public:
FlatColorShader(void)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 
setColor(sglr::Context & gl,deUint32 program,const tcu::Vec4 & color)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 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const93 	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 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const99 	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 
111 class SingleTex2DShader : public sglr::ShaderProgram
112 {
113 public:
SingleTex2DShader(void)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 
setUnit(sglr::Context & gl,deUint32 program,int unitNdx)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 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const146 	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 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const157 	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 
171 class MixTexturesShader : public sglr::ShaderProgram
172 {
173 public:
MixTexturesShader(void)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 
setUnits(sglr::Context & gl,deUint32 program,int unit0,int unit1)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 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const209 	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 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const220 	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 
236 class FboConfig
237 {
238 public:
FboConfig(void)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 
260 private:
261 	static const char*		getFormatName	(GLenum format);
262 };
263 
getFormatName(GLenum format)264 const 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 
getName(void) const284 std::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 
319 class FboIncompleteException : public tcu::TestError
320 {
321 public:
322 						FboIncompleteException		(const FboConfig& config, GLenum reason, const char* file, int line);
~FboIncompleteException(void)323 	virtual				~FboIncompleteException		(void) throw() {}
324 
getConfig(void) const325 	const FboConfig&	getConfig					(void) const { return m_config; }
getReason(void) const326 	GLenum				getReason					(void) const { return m_reason; }
327 
328 private:
329 	FboConfig			m_config;
330 	GLenum				m_reason;
331 };
332 
getFboIncompleteReasonName(GLenum reason)333 static 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 
FboIncompleteException(const FboConfig & config,GLenum reason,const char * file,int line)346 FboIncompleteException::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 
353 class Framebuffer
354 {
355 public:
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 
getConfig(void) const359 	const FboConfig&	getConfig			(void) const { return m_config; }
getFramebuffer(void) const360 	deUint32			getFramebuffer		(void) const { return m_framebuffer; }
getColorbuffer(void) const361 	deUint32			getColorbuffer		(void) const { return m_colorbuffer; }
getDepthbuffer(void) const362 	deUint32			getDepthbuffer		(void) const { return m_depthbuffer; }
getStencilbuffer(void) const363 	deUint32			getStencilbuffer	(void) const { return m_stencilbuffer; }
364 
365 	void				checkCompleteness	(void);
366 
367 private:
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 
isExtensionSupported(sglr::Context & context,const char * name)379 static 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 
checkColorFormatSupport(sglr::Context & context,deUint32 sizedFormat)393 static 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 
Framebuffer(sglr::Context & context,const FboConfig & config,int width,int height,deUint32 fbo,deUint32 colorbuffer,deUint32 depthbuffer,deUint32 stencilbuffer)409 Framebuffer::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 
~Framebuffer(void)476 Framebuffer::~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 
checkCompleteness(void)484 void 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 
createRbo(deUint32 & name,GLenum format,int width,int height)493 void 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 
destroyBuffer(deUint32 name,GLenum type)501 void 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 
createMetaballsTex2D(sglr::Context & context,deUint32 name,GLenum format,GLenum dataType,int width,int height)511 static 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 
createQuadsTex2D(sglr::Context & context,deUint32 name,GLenum format,GLenum dataType,int width,int height)523 static 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 
535 class FboRenderCase : public TestCase
536 {
537 public:
538 								FboRenderCase			(Context& context, const char* name, const char* description, const FboConfig& config);
~FboRenderCase(void)539 	virtual						~FboRenderCase			(void) {}
540 
541 	virtual IterateResult		iterate					(void);
542 	virtual void				render					(sglr::Context& fboContext, Surface& dst) = DE_NULL;
543 
getConfig(void) const544 	const FboConfig&			getConfig				(void) const { return m_config; }
545 
isConfigSupported(const FboConfig & config)546 	static bool					isConfigSupported		(const FboConfig& config) { DE_UNREF(config); return true; }
547 
548 private:
549 	FboConfig					m_config;
550 };
551 
FboRenderCase(Context & context,const char * name,const char * description,const FboConfig & config)552 FboRenderCase::FboRenderCase (Context& context, const char* name, const char* description, const FboConfig& config)
553 	: TestCase(context, name, description)
554 	, m_config(config)
555 {
556 }
557 
iterate(void)558 TestCase::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 
642 namespace FboCases
643 {
644 
645 class ColorClearsTest : public FboRenderCase
646 {
647 public:
648 						ColorClearsTest				(Context& context, const FboConfig& config);
~ColorClearsTest(void)649 						~ColorClearsTest			(void) {}
650 
651 	void				render						(sglr::Context& context, Surface& dst);
652 };
653 
ColorClearsTest(Context & context,const FboConfig & config)654 ColorClearsTest::ColorClearsTest (Context& context, const FboConfig& config)
655 	: FboRenderCase(context, config.getName().c_str(), "Color buffer clears", config)
656 {
657 }
658 
render(sglr::Context & context,Surface & dst)659 void 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 
732 class IntersectingQuadsTest : public FboRenderCase
733 {
734 public:
735 					IntersectingQuadsTest			(Context& context, const FboConfig& config, bool npot = false);
~IntersectingQuadsTest(void)736 	virtual			~IntersectingQuadsTest			(void) {}
737 
738 	virtual void	render							(sglr::Context& context, Surface& dst);
739 
740 	static bool		isConfigSupported				(const FboConfig& config);
741 
742 private:
743 	int				m_fboWidth;
744 	int				m_fboHeight;
745 };
746 
747 class IntersectingQuadsNpotTest : public IntersectingQuadsTest
748 {
749 public:
IntersectingQuadsNpotTest(Context & context,const FboConfig & config)750 	IntersectingQuadsNpotTest (Context& context, const FboConfig& config)
751 		: IntersectingQuadsTest(context, config, true)
752 	{
753 	}
754 };
755 
IntersectingQuadsTest(Context & context,const FboConfig & config,bool npot)756 IntersectingQuadsTest::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 
isConfigSupported(const FboConfig & config)763 bool 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 
render(sglr::Context & ctx,Surface & dst)770 void 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 
825 class MixTest : public FboRenderCase
826 {
827 public:
828 						MixTest				(Context& context, const FboConfig& config, bool npot = false);
~MixTest(void)829 	virtual				~MixTest			(void) {}
830 
831 	void				render				(sglr::Context& context, Surface& dst);
832 
833 	static bool			isConfigSupported	(const FboConfig& config);
834 
835 private:
836 	int					m_fboAWidth;
837 	int					m_fboAHeight;
838 	int					m_fboBWidth;
839 	int					m_fboBHeight;
840 };
841 
842 class MixNpotTest : public MixTest
843 {
844 public:
MixNpotTest(Context & context,const FboConfig & config)845 	MixNpotTest (Context& context, const FboConfig& config)
846 		: MixTest(context, config, true)
847 	{
848 	}
849 };
850 
MixTest(Context & context,const FboConfig & config,bool npot)851 MixTest::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 
isConfigSupported(const FboConfig & config)860 bool 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 
render(sglr::Context & context,Surface & dst)867 void 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 
920 class BlendTest : public FboRenderCase
921 {
922 public:
923 						BlendTest			(Context& context, const FboConfig& config, bool npot = false);
~BlendTest(void)924 	virtual				~BlendTest			(void) {}
925 
926 	void				render				(sglr::Context& context, Surface& dst);
927 
928 	static bool			isConfigSupported	(const FboConfig& config);
929 
930 private:
931 	int					m_fboWidth;
932 	int					m_fboHeight;
933 };
934 
935 class BlendNpotTest : public BlendTest
936 {
937 public:
BlendNpotTest(Context & context,const FboConfig & config)938 	BlendNpotTest (Context& context, const FboConfig& config)
939 		: BlendTest(context, config, true)
940 	{
941 	}
942 };
943 
BlendTest(Context & context,const FboConfig & config,bool npot)944 BlendTest::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 
isConfigSupported(const FboConfig & config)951 bool 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 
render(sglr::Context & context,Surface & dst)957 void 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 
996 class StencilClearsTest : public FboRenderCase
997 {
998 public:
999 						StencilClearsTest		(Context& context, const FboConfig& config);
~StencilClearsTest(void)1000 	virtual				~StencilClearsTest		(void) {};
1001 
1002 	void				render					(sglr::Context& context, Surface& dst);
1003 
1004 	static bool			isConfigSupported		(const FboConfig& config);
1005 };
1006 
StencilClearsTest(Context & context,const FboConfig & config)1007 StencilClearsTest::StencilClearsTest (Context& context, const FboConfig& config)
1008 	: FboRenderCase(context, config.getName().c_str(), "Stencil clears", config)
1009 {
1010 }
1011 
render(sglr::Context & context,Surface & dst)1012 void 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 
isConfigSupported(const FboConfig & config)1086 bool StencilClearsTest::isConfigSupported (const FboConfig& config)
1087 {
1088 	return config.stencilbufferType != GL_NONE;
1089 }
1090 
1091 class StencilTest : public FboRenderCase
1092 {
1093 public:
1094 						StencilTest				(Context& context, const FboConfig& config, bool npot = false);
~StencilTest(void)1095 	virtual				~StencilTest			(void) {};
1096 
1097 	void				render					(sglr::Context& context, Surface& dst);
1098 
1099 	static bool			isConfigSupported		(const FboConfig& config);
1100 
1101 private:
1102 	int					m_fboWidth;
1103 	int					m_fboHeight;
1104 };
1105 
1106 class StencilNpotTest : public StencilTest
1107 {
1108 public:
StencilNpotTest(Context & context,const FboConfig & config)1109 	StencilNpotTest (Context& context, const FboConfig& config)
1110 		: StencilTest(context, config, true)
1111 	{
1112 	}
1113 };
1114 
StencilTest(Context & context,const FboConfig & config,bool npot)1115 StencilTest::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 
isConfigSupported(const FboConfig & config)1122 bool StencilTest::isConfigSupported (const FboConfig& config)
1123 {
1124 	return config.stencilbufferType != GL_NONE;
1125 }
1126 
render(sglr::Context & ctx,Surface & dst)1127 void 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 
1194 class SharedColorbufferTest : public FboRenderCase
1195 {
1196 public:
1197 						SharedColorbufferTest			(Context& context, const FboConfig& config);
~SharedColorbufferTest(void)1198 	virtual				~SharedColorbufferTest			(void) {};
1199 
1200 	void				render							(sglr::Context& context, Surface& dst);
1201 };
1202 
SharedColorbufferTest(Context & context,const FboConfig & config)1203 SharedColorbufferTest::SharedColorbufferTest (Context& context, const FboConfig& config)
1204 	: FboRenderCase(context, config.getName().c_str(), "Shared colorbuffer", config)
1205 {
1206 }
1207 
render(sglr::Context & context,Surface & dst)1208 void 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 
1320 class SharedColorbufferClearsTest : public FboRenderCase
1321 {
1322 public:
1323 					SharedColorbufferClearsTest		(Context& context, const FboConfig& config);
~SharedColorbufferClearsTest(void)1324 	virtual			~SharedColorbufferClearsTest	(void) {}
1325 
1326 	static bool		isConfigSupported				(const FboConfig& config);
1327 	void			render							(sglr::Context& context, Surface& dst);
1328 };
1329 
SharedColorbufferClearsTest(Context & context,const FboConfig & config)1330 SharedColorbufferClearsTest::SharedColorbufferClearsTest (Context& context, const FboConfig& config)
1331 	: FboRenderCase(context, config.getName().c_str(), "Shared colorbuffer clears", config)
1332 {
1333 }
1334 
isConfigSupported(const FboConfig & config)1335 bool SharedColorbufferClearsTest::isConfigSupported (const FboConfig& config)
1336 {
1337 	return config.colorbufferType	!= GL_NONE &&
1338 		   config.depthbufferType	== GL_NONE &&
1339 		   config.stencilbufferType	== GL_NONE;
1340 }
1341 
render(sglr::Context & context,Surface & dst)1342 void 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 
1427 class SharedDepthbufferTest : public FboRenderCase
1428 {
1429 public:
1430 					SharedDepthbufferTest		(Context& context, const FboConfig& config);
~SharedDepthbufferTest(void)1431 	virtual			~SharedDepthbufferTest		(void) {};
1432 
1433 	static bool		isConfigSupported			(const FboConfig& config);
1434 	void			render						(sglr::Context& context, Surface& dst);
1435 };
1436 
SharedDepthbufferTest(Context & context,const FboConfig & config)1437 SharedDepthbufferTest::SharedDepthbufferTest (Context& context, const FboConfig& config)
1438 	: FboRenderCase(context, config.getName().c_str(), "Shared depthbuffer", config)
1439 {
1440 }
1441 
isConfigSupported(const FboConfig & config)1442 bool SharedDepthbufferTest::isConfigSupported (const FboConfig& config)
1443 {
1444 	return config.depthbufferType == GL_RENDERBUFFER;
1445 }
1446 
render(sglr::Context & context,Surface & dst)1447 void 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 
1541 class TexSubImageAfterRenderTest : public FboRenderCase
1542 {
1543 public:
1544 					TexSubImageAfterRenderTest		(Context& context, const FboConfig& config);
~TexSubImageAfterRenderTest(void)1545 	virtual			~TexSubImageAfterRenderTest		(void) {}
1546 
1547 	static bool		isConfigSupported				(const FboConfig& config);
1548 	void			render							(sglr::Context& context, Surface& dst);
1549 };
1550 
TexSubImageAfterRenderTest(Context & context,const FboConfig & config)1551 TexSubImageAfterRenderTest::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 
isConfigSupported(const FboConfig & config)1556 bool 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 
render(sglr::Context & context,Surface & dst)1564 void 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 
1607 class TexSubImageBetweenRenderTest : public FboRenderCase
1608 {
1609 public:
1610 					TexSubImageBetweenRenderTest		(Context& context, const FboConfig& config);
~TexSubImageBetweenRenderTest(void)1611 	virtual			~TexSubImageBetweenRenderTest		(void) {}
1612 
1613 	static bool		isConfigSupported					(const FboConfig& config);
1614 	void			render								(sglr::Context& context, Surface& dst);
1615 };
1616 
TexSubImageBetweenRenderTest(Context & context,const FboConfig & config)1617 TexSubImageBetweenRenderTest::TexSubImageBetweenRenderTest (Context& context, const FboConfig& config)
1618 	: FboRenderCase(context, (string("between_render_") + config.getName()).c_str(), "TexSubImage between rendering calls", config)
1619 {
1620 }
1621 
isConfigSupported(const FboConfig & config)1622 bool 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 
render(sglr::Context & context,Surface & dst)1630 void 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 
1690 class ResizeTest : public FboRenderCase
1691 {
1692 public:
1693 					ResizeTest				(Context& context, const FboConfig& config);
~ResizeTest(void)1694 	virtual			~ResizeTest				(void) {}
1695 
1696 	void			render					(sglr::Context& context, Surface& dst);
1697 };
1698 
ResizeTest(Context & context,const FboConfig & config)1699 ResizeTest::ResizeTest (Context& context, const FboConfig& config)
1700 	: FboRenderCase(context, config.getName().c_str(), "Resize framebuffer", config)
1701 {
1702 }
1703 
render(sglr::Context & context,Surface & dst)1704 void 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 
1820 template <GLenum Buffers>
1821 class RecreateBuffersTest : public FboRenderCase
1822 {
1823 public:
1824 					RecreateBuffersTest			(Context& context, const FboConfig& config, bool rebind);
~RecreateBuffersTest(void)1825 	virtual			~RecreateBuffersTest		(void) {}
1826 
1827 	static bool		isConfigSupported			(const FboConfig& config);
1828 	void			render						(sglr::Context& context, Surface& dst);
1829 
1830 private:
1831 	bool			m_rebind;
1832 };
1833 
1834 template <GLenum Buffers>
1835 class RecreateBuffersNoRebindTest : public RecreateBuffersTest<Buffers>
1836 {
1837 public:
RecreateBuffersNoRebindTest(Context & context,const FboConfig & config)1838 	RecreateBuffersNoRebindTest (Context& context, const FboConfig& config)
1839 		: RecreateBuffersTest<Buffers>(context, config, false)
1840 	{
1841 	}
1842 };
1843 
1844 template <GLenum Buffers>
1845 class RecreateBuffersRebindTest : public RecreateBuffersTest<Buffers>
1846 {
1847 public:
RecreateBuffersRebindTest(Context & context,const FboConfig & config)1848 	RecreateBuffersRebindTest (Context& context, const FboConfig& config)
1849 		: RecreateBuffersTest<Buffers>(context, config, true)
1850 	{
1851 	}
1852 };
1853 
1854 template <GLenum Buffers>
RecreateBuffersTest(Context & context,const FboConfig & config,bool rebind)1855 RecreateBuffersTest<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 
1861 template <GLenum Buffers>
isConfigSupported(const FboConfig & config)1862 bool 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 
1873 template <GLenum Buffers>
render(sglr::Context & ctx,Surface & dst)1874 void 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 
1996 class RepeatedClearCase : public FboRenderCase
1997 {
1998 private:
makeConfig(deUint32 format)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 
2009 public:
RepeatedClearCase(Context & context,deUint32 format)2010 	RepeatedClearCase (Context& context, deUint32 format)
2011 		: FboRenderCase(context, makeConfig(format).getName().c_str(), "Repeated clears", makeConfig(format))
2012 	{
2013 	}
2014 
2015 protected:
render(sglr::Context & ctx,Surface & dst)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 
FboRenderTestGroup(Context & context)2082 FboRenderTestGroup::FboRenderTestGroup (Context& context)
2083 	: TestCaseGroup(context, "render", "Rendering Tests")
2084 {
2085 }
2086 
~FboRenderTestGroup(void)2087 FboRenderTestGroup::~FboRenderTestGroup (void)
2088 {
2089 }
2090 
2091 namespace
2092 {
2093 
2094 struct TypeFormatPair
2095 {
2096 	GLenum		type;
2097 	GLenum		format;
2098 };
2099 
2100 template <typename CaseType>
addChildVariants(deqp::gles2::TestCaseGroup * group)2101 void 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 
2144 template <typename CaseType>
createChildGroup(deqp::gles2::TestCaseGroup * parent,const char * name,const char * description)2145 void 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 
2152 template <GLbitfield Buffers>
createRecreateBuffersGroup(deqp::gles2::TestCaseGroup * parent,const char * name,const char * description)2153 void 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 
init(void)2163 void 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