Home | History | Annotate | Download | only in glshared
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL (ES) 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 GLES Scissor tests
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "glsScissorTests.hpp"
     25 #include "glsTextureTestUtil.hpp"
     26 
     27 #include "deMath.h"
     28 #include "deRandom.hpp"
     29 #include "deUniquePtr.hpp"
     30 
     31 #include "tcuTestCase.hpp"
     32 #include "tcuImageCompare.hpp"
     33 #include "tcuVector.hpp"
     34 #include "tcuVectorUtil.hpp"
     35 #include "tcuTexture.hpp"
     36 #include "tcuStringTemplate.hpp"
     37 
     38 #include "gluStrUtil.hpp"
     39 #include "gluDrawUtil.hpp"
     40 #include "gluPixelTransfer.hpp"
     41 #include "gluObjectWrapper.hpp"
     42 
     43 #include "glwEnums.hpp"
     44 #include "glwFunctions.hpp"
     45 
     46 #include <map>
     47 
     48 namespace deqp
     49 {
     50 namespace gls
     51 {
     52 namespace Functional
     53 {
     54 namespace
     55 {
     56 
     57 using namespace ScissorTestInternal;
     58 using namespace glw; // GL types
     59 
     60 using tcu::ConstPixelBufferAccess;
     61 using tcu::PixelBufferAccess;
     62 using tcu::TestLog;
     63 
     64 using std::vector;
     65 using std::string;
     66 using std::map;
     67 using tcu::Vec3;
     68 using tcu::Vec4;
     69 using tcu::IVec4;
     70 using tcu::UVec4;
     71 
     72 void drawQuad (const glw::Functions& gl, deUint32 program, const Vec3& p0, const Vec3& p1)
     73 {
     74 	// Vertex data.
     75 	const float hz = (p0.z() + p1.z()) * 0.5f;
     76 	const float position[] =
     77 	{
     78 		p0.x(), p0.y(), p0.z(),	1.0f,
     79 		p0.x(), p1.y(), hz,		1.0f,
     80 		p1.x(), p0.y(), hz,		1.0f,
     81 		p1.x(), p1.y(), p1.z(),	1.0f
     82 	};
     83 
     84 	const deUint16	indices[]	= { 0, 1, 2, 2, 1, 3 };
     85 
     86 	const deInt32	posLoc		= gl.getAttribLocation(program, "a_position");
     87 
     88 	gl.useProgram(program);
     89 	gl.enableVertexAttribArray(posLoc);
     90 	gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
     91 
     92 	gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]);
     93 
     94 	gl.disableVertexAttribArray(posLoc);
     95 
     96 }
     97 
     98 void drawPrimitives (const glw::Functions& gl, deUint32 program, const deUint32 type, const vector<float>& vertices, const vector<deUint16>& indices)
     99 {
    100 	const deInt32 posLoc = gl.getAttribLocation(program, "a_position");
    101 
    102 	TCU_CHECK(posLoc >= 0);
    103 
    104 	gl.useProgram(program);
    105 	gl.enableVertexAttribArray(posLoc);
    106 	gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &vertices[0]);
    107 
    108 	gl.drawElements(type, GLsizei(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
    109 
    110 	gl.disableVertexAttribArray(posLoc);
    111 }
    112 
    113 template<typename T>
    114 void clearEdges (const tcu::PixelBufferAccess& access, const T& color, const IVec4& scissorArea)
    115 {
    116 	for (int y = 0; y < access.getHeight(); y++)
    117 	for (int x = 0; x < access.getWidth(); x++)
    118 	{
    119 		if (y < scissorArea.y() ||
    120 			y >= scissorArea.y() + scissorArea.w() ||
    121 			x < scissorArea.x() ||
    122 			x >= scissorArea.x()+ scissorArea.z())
    123 			access.setPixel(color, x, y);
    124 	}
    125 }
    126 
    127 glu::ProgramSources genShaders(glu::GLSLVersion version)
    128 {
    129 	const string vtxSource = "${VERSION}\n"
    130 							 "${IN} highp vec4 a_position;\n"
    131 							 "void main(){\n"
    132 							 "	gl_Position = a_position;\n"
    133 							 "}\n";
    134 
    135 	const string frgSource = "${VERSION}\n"
    136 							 "${OUT_DECL}"
    137 							 "uniform highp vec4 u_color;\n"
    138 							 "void main(){\n"
    139 							 "	${OUTPUT} = u_color;\n"
    140 							 "}\n";
    141 
    142 	map<string, string>	params;
    143 
    144 	switch(version)
    145 	{
    146 		case glu::GLSL_VERSION_100_ES:
    147 			params["VERSION"] = "#version 100";
    148 			params["IN"] = "attribute";
    149 			params["OUT_DECL"] = "";
    150 			params["OUTPUT"] = "gl_FragColor";
    151 			break;
    152 
    153 		case glu::GLSL_VERSION_300_ES:
    154 		case glu::GLSL_VERSION_310_ES: // Assumed to support 3.0
    155 			params["VERSION"] = "#version 300 es";
    156 			params["IN"] = "in";
    157 			params["OUT_DECL"] = "out mediump vec4 f_color;\n";
    158 			params["OUTPUT"] = "f_color";
    159 			break;
    160 
    161 		default:
    162 			DE_ASSERT(!"Unsupported version");
    163 	}
    164 
    165 	return glu::makeVtxFragSources(tcu::StringTemplate(vtxSource).specialize(params), tcu::StringTemplate(frgSource).specialize(params));
    166 }
    167 
    168 // Wrapper class, provides iterator & reporting logic
    169 class ScissorCase : public tcu::TestCase
    170 {
    171 public:
    172 							ScissorCase		(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char *name, const char* desc, const Vec4& scissorArea);
    173 	virtual					~ScissorCase	(void) {}
    174 
    175 	virtual IterateResult	iterate			(void);
    176 
    177 protected:
    178 	virtual void			render			(GLuint program, const IVec4& viewport) const = 0;
    179 
    180 	glu::RenderContext&		m_renderCtx;
    181 	const Vec4				m_scissorArea;
    182 };
    183 
    184 ScissorCase::ScissorCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char *name, const char* desc, const Vec4& scissorArea)
    185 	: TestCase		(testCtx, name, desc)
    186 	, m_renderCtx	(renderCtx)
    187 	, m_scissorArea	(scissorArea)
    188 {
    189 }
    190 
    191 ScissorCase::IterateResult ScissorCase::iterate (void)
    192 {
    193 	using TextureTestUtil::RandomViewport;
    194 
    195 	const glw::Functions&		gl				= m_renderCtx.getFunctions();
    196 	TestLog&					log				= m_testCtx.getLog();
    197 	const tcu::PixelFormat		renderFormat	= m_renderCtx.getRenderTarget().getPixelFormat();
    198 	const tcu::Vec4				threshold		= 0.02f * UVec4(1u << de::max(0, 8 - renderFormat.redBits),
    199 																1u << de::max(0, 8 - renderFormat.greenBits),
    200 																1u << de::max(0, 8 - renderFormat.blueBits),
    201 																1u << de::max(0, 8 - renderFormat.alphaBits)).asFloat();
    202 	const glu::ShaderProgram	shader			(m_renderCtx, genShaders(glu::getContextTypeGLSLVersion(m_renderCtx.getType())));
    203 
    204 	const RandomViewport		viewport		(m_renderCtx.getRenderTarget(), 256, 256, deStringHash(getName()));
    205 	const IVec4					relScissorArea	(int(m_scissorArea.x()*viewport.width),
    206 												 int(m_scissorArea.y()*viewport.height),
    207 												 int(m_scissorArea.z()*viewport.width),
    208 												 int(m_scissorArea.w()*viewport.height));
    209 	const IVec4					absScissorArea	(relScissorArea.x() + viewport.x,
    210 												 relScissorArea.y() + viewport.y,
    211 												 relScissorArea.z(),
    212 												 relScissorArea.w());
    213 
    214 	tcu::Surface				refImage		(viewport.width, viewport.height);
    215 	tcu::Surface				resImage		(viewport.width, viewport.height);
    216 
    217 	if (!shader.isOk())
    218 	{
    219 		log << shader;
    220 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader compile/link failed");
    221 		return STOP;
    222 	}
    223 
    224 	log << TestLog::Message << "Viewport area is " << IVec4(viewport.x, viewport.y, viewport.width, viewport.height) << TestLog::EndMessage;
    225 	log << TestLog::Message << "Scissor area is " << absScissorArea << TestLog::EndMessage;
    226 
    227 	// Render reference (no scissors)
    228 	{
    229 		log << TestLog::Message << "Rendering reference (scissors disabled)" << TestLog::EndMessage;
    230 
    231 		gl.useProgram(shader.getProgram());
    232 		gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
    233 
    234 		gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
    235 		gl.clearDepthf(1.0f);
    236 		gl.clearStencil(0);
    237 		gl.disable(GL_DEPTH_TEST);
    238 		gl.disable(GL_STENCIL_TEST);
    239 		gl.disable(GL_SCISSOR_TEST);
    240 		gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    241 
    242 		render(shader.getProgram(), IVec4(viewport.x, viewport.y, viewport.width, viewport.height));
    243 
    244 		glu::readPixels(m_renderCtx, viewport.x, viewport.y, refImage.getAccess());
    245 		GLU_CHECK_ERROR(gl.getError());
    246 	}
    247 
    248 	// Render result (scissors)
    249 	{
    250 		log << TestLog::Message << "Rendering result (scissors enabled)" << TestLog::EndMessage;
    251 
    252 		gl.useProgram(shader.getProgram());
    253 		gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
    254 
    255 		gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
    256 		gl.clearDepthf(1.0f);
    257 		gl.clearStencil(0);
    258 		gl.disable(GL_DEPTH_TEST);
    259 		gl.disable(GL_STENCIL_TEST);
    260 		gl.disable(GL_SCISSOR_TEST);
    261 		gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    262 
    263 		gl.scissor(absScissorArea.x(), absScissorArea.y(), absScissorArea.z(), absScissorArea.w());
    264 		gl.enable(GL_SCISSOR_TEST);
    265 
    266 		render(shader.getProgram(), IVec4(viewport.x, viewport.y, viewport.width, viewport.height));
    267 
    268 		glu::readPixels(m_renderCtx, viewport.x, viewport.y, resImage.getAccess());
    269 		GLU_CHECK_ERROR(gl.getError());
    270 	}
    271 
    272 	// Manual 'scissors' for reference image
    273 	log << TestLog::Message << "Clearing area outside scissor area from reference" << TestLog::EndMessage;
    274 	clearEdges(refImage.getAccess(), IVec4(32, 64, 128, 255), relScissorArea);
    275 
    276 	if (tcu::floatThresholdCompare(log, "ComparisonResult", "Image comparison result", refImage.getAccess(), resImage.getAccess(), threshold, tcu::COMPARE_LOG_RESULT))
    277 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    278 	else
    279 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
    280 
    281 	return STOP;
    282 }
    283 
    284 // Tests scissoring with multiple primitive types
    285 class ScissorPrimitiveCase : public ScissorCase
    286 {
    287 public:
    288 								ScissorPrimitiveCase	(tcu::TestContext&		testCtx,
    289 														 glu::RenderContext&	renderCtx,
    290 														 const char*			name,
    291 														 const char*			desc,
    292 														 const Vec4&			scissorArea,
    293 														 const Vec4&			renderArea,
    294 														 PrimitiveType			type,
    295 														 int					primitiveCount);
    296 	virtual						~ScissorPrimitiveCase	(void){}
    297 
    298 protected:
    299 	virtual void				render					(GLuint program, const IVec4& viewport) const;
    300 
    301 private:
    302 	const Vec4					m_renderArea;
    303 	const PrimitiveType			m_primitiveType;
    304 	const int					m_primitiveCount;
    305 };
    306 
    307 ScissorPrimitiveCase::ScissorPrimitiveCase	(tcu::TestContext&		testCtx,
    308 											 glu::RenderContext&	renderCtx,
    309 											 const char*			name,
    310 											 const char*			desc,
    311 											 const Vec4&			scissorArea,
    312 											 const Vec4&			renderArea,
    313 											 PrimitiveType			type,
    314 											 int					primitiveCount)
    315 	: ScissorCase		(testCtx, renderCtx, name, desc, scissorArea)
    316 	, m_renderArea		(renderArea)
    317 	, m_primitiveType	(type)
    318 	, m_primitiveCount	(primitiveCount)
    319 {
    320 }
    321 
    322 void ScissorPrimitiveCase::render (GLuint program, const IVec4&) const
    323 {
    324 	const glw::Functions&		gl				= m_renderCtx.getFunctions();
    325 	const Vec4					white			(1.0f, 1.0f, 1.0f, 1.0);
    326 	const Vec4					primitiveArea	(m_renderArea.x()*2.0f-1.0f,
    327 												 m_renderArea.x()*2.0f-1.0f,
    328 												 m_renderArea.z()*2.0f,
    329 												 m_renderArea.w()*2.0f);
    330 
    331 	static const float quadPositions[] =
    332 	{
    333 		 0.0f,  1.0f,
    334 		 0.0f,  0.0f,
    335 		 1.0f,  1.0f,
    336 		 1.0f,  0.0f
    337 	};
    338 	static const float triPositions[] =
    339 	{
    340 		 0.0f,  0.0f,
    341 		 1.0f,  0.0f,
    342 		 0.5f,  1.0f,
    343 	};
    344 	static const float linePositions[] =
    345 	{
    346 		 0.0f,  0.0f,
    347 		 1.0f,  1.0f
    348 	};
    349 	static const float pointPosition[] =
    350 	{
    351 		 0.5f,  0.5f
    352 	};
    353 
    354 	const float*		positionSet[]	= { pointPosition, linePositions, triPositions, quadPositions };
    355 	const int			vertexCountSet[]= { 1, 2, 3, 4 };
    356 	const int			indexCountSet[]	= { 1, 2, 3, 6 };
    357 
    358 	const deUint16		baseIndices[]	= { 0, 1, 2, 2, 1, 3 };
    359 	const float*		basePositions	= positionSet[m_primitiveType];
    360 	const int			vertexCount		= vertexCountSet[m_primitiveType];
    361 	const int			indexCount		= indexCountSet[m_primitiveType];
    362 
    363 	const float			scale			= 1.44f/deFloatSqrt(float(m_primitiveCount)*2.0f); // Magic value to roughly fill the render area with primitives at a readable density
    364 	vector<float>		positions		(4*vertexCount*m_primitiveCount);
    365 	vector<deUint16>	indices			(indexCount*m_primitiveCount);
    366 	de::Random			rng				(1234);
    367 
    368 	for (int primNdx = 0; primNdx < m_primitiveCount; primNdx++)
    369 	{
    370 		const float dx = m_primitiveCount>1 ? rng.getFloat() : 0.0f;
    371 		const float dy = m_primitiveCount>1 ? rng.getFloat() : 0.0f;
    372 
    373 		for (int vertNdx = 0; vertNdx < vertexCount; vertNdx++)
    374 		{
    375 			const int ndx = primNdx*4*vertexCount + vertNdx*4;
    376 			positions[ndx+0] = (basePositions[vertNdx*2 + 0]*scale + dx)*primitiveArea.z() + primitiveArea.x();
    377 			positions[ndx+1] = (basePositions[vertNdx*2 + 1]*scale + dy)*primitiveArea.w() + primitiveArea.y();
    378 			positions[ndx+2] = 0.2f;
    379 			positions[ndx+3] = 1.0f;
    380 		}
    381 
    382 		for (int ndx = 0; ndx < indexCount; ndx++)
    383 			indices[primNdx*indexCount + ndx] = baseIndices[ndx] + primNdx*vertexCount;
    384 	}
    385 
    386 	gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, white.m_data);
    387 
    388 	switch (m_primitiveType)
    389 	{
    390 		case TRIANGLE:	drawPrimitives(gl, program, GL_TRIANGLES,	positions, indices);	break;
    391 		case LINE:		drawPrimitives(gl, program, GL_LINES,		positions, indices);	break;
    392 		case POINT:		drawPrimitives(gl, program, GL_POINTS,		positions, indices);	break;
    393 		default:		DE_ASSERT(false);													break;
    394 	}
    395 }
    396 
    397 // Test effect of scissor on default framebuffer clears
    398 class ScissorClearCase : public ScissorCase
    399 {
    400 public:
    401 					ScissorClearCase	(tcu::TestContext&		testCtx,
    402 										 glu::RenderContext&	renderCtx,
    403 										 const char*			name,
    404 										 const char*			desc,
    405 										 const Vec4&			scissorArea,
    406 										 deUint32				clearMode);
    407 	virtual			~ScissorClearCase	(void) {}
    408 
    409 	virtual void	init				(void);
    410 
    411 protected:
    412 	virtual void	render				(GLuint program, const IVec4& viewport) const;
    413 
    414 private:
    415 	const deUint32	m_clearMode; //!< Combination of the flags accepted by glClear
    416 };
    417 
    418 ScissorClearCase::ScissorClearCase	(tcu::TestContext&		testCtx,
    419 									 glu::RenderContext&	renderCtx,
    420 									 const char*			name,
    421 									 const char*			desc,
    422 									 const Vec4&			scissorArea,
    423 									 deUint32				clearMode)
    424 	: ScissorCase	(testCtx, renderCtx, name, desc, scissorArea)
    425 	, m_clearMode	(clearMode)
    426 {
    427 }
    428 
    429 void ScissorClearCase::init (void)
    430 {
    431 	if ((m_clearMode & GL_DEPTH_BUFFER_BIT) && m_renderCtx.getRenderTarget().getDepthBits() == 0)
    432 		throw tcu::NotSupportedError("Cannot clear depth; no depth buffer present", "", __FILE__, __LINE__);
    433 	else if ((m_clearMode & GL_STENCIL_BUFFER_BIT) && m_renderCtx.getRenderTarget().getStencilBits() == 0)
    434 		throw tcu::NotSupportedError("Cannot clear stencil; no stencil buffer present", "", __FILE__, __LINE__);
    435 }
    436 
    437 void ScissorClearCase::render (GLuint program, const IVec4&) const
    438 {
    439 	const glw::Functions&	gl		= m_renderCtx.getFunctions();
    440 	const Vec4				white	(1.0f, 1.0f, 1.0f, 1.0);
    441 
    442 	gl.clearColor(0.6f, 0.1f, 0.1f, 1.0);
    443 	gl.clearDepthf(0.0f);
    444 
    445 	if (m_clearMode & GL_DEPTH_BUFFER_BIT)
    446 	{
    447 		gl.enable(GL_DEPTH_TEST);
    448 		gl.depthFunc(GL_GREATER);
    449 	}
    450 
    451 	if (m_clearMode & GL_STENCIL_BUFFER_BIT)
    452 	{
    453 		gl.clearStencil(123);
    454 		gl.enable(GL_STENCIL_TEST);
    455 		gl.stencilFunc(GL_EQUAL, 123, ~0u);
    456 	}
    457 
    458 	if (m_clearMode & GL_COLOR_BUFFER_BIT)
    459 		gl.clearColor(0.1f, 0.6f, 0.1f, 1.0);
    460 
    461 	gl.clear(m_clearMode);
    462 	gl.disable(GL_SCISSOR_TEST);
    463 
    464 	gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, white.getPtr());
    465 
    466 	if (!(m_clearMode & GL_COLOR_BUFFER_BIT))
    467 		drawQuad(gl, program, Vec3(-1.0f, -1.0f, 0.5f), Vec3(1.0f, 1.0f, 0.5f));
    468 
    469 	gl.disable(GL_DEPTH_TEST);
    470 	gl.disable(GL_STENCIL_TEST);
    471 }
    472 
    473 class FramebufferBlitCase : public ScissorCase
    474 {
    475 public:
    476 					FramebufferBlitCase		(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, const Vec4& scissorArea);
    477 	virtual			~FramebufferBlitCase	(void) {}
    478 
    479 	virtual void	init					(void);
    480 	virtual void	deinit					(void);
    481 
    482 protected:
    483 	typedef de::MovePtr<glu::Framebuffer> FramebufferP;
    484 
    485 	enum {SIZE = 64};
    486 
    487 	virtual void	render					(GLuint program, const IVec4& viewport) const;
    488 
    489 	FramebufferP	m_fbo;
    490 };
    491 
    492 FramebufferBlitCase::FramebufferBlitCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, const Vec4& scissorArea)
    493 	: ScissorCase(testCtx, renderCtx, name, desc, scissorArea)
    494 {
    495 }
    496 
    497 void FramebufferBlitCase::init (void)
    498 {
    499 	if (m_renderCtx.getRenderTarget().getNumSamples())
    500 		throw tcu::NotSupportedError("Cannot blit to multisampled framebuffer", "", __FILE__, __LINE__);
    501 
    502 	const glw::Functions&	gl			= m_renderCtx.getFunctions();
    503 	const glu::Renderbuffer	colorbuf	(gl);
    504 	const tcu::Vec4			clearColor	(1.0f, 0.5, 0.125f, 1.0f);
    505 
    506 	m_fbo = FramebufferP(new glu::Framebuffer(gl));
    507 
    508 	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, **m_fbo);
    509 
    510 	gl.bindRenderbuffer(GL_RENDERBUFFER, *colorbuf);
    511 	gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, SIZE, SIZE);
    512 	gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorbuf);
    513 
    514 	gl.clearBufferfv(GL_COLOR, 0, clearColor.getPtr());
    515 	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_renderCtx.getDefaultFramebuffer());
    516 }
    517 
    518 void FramebufferBlitCase::deinit (void)
    519 {
    520 	m_fbo.clear();
    521 }
    522 
    523 void FramebufferBlitCase::render(GLuint program, const IVec4& viewport) const
    524 {
    525 	const glw::Functions&	gl					= m_renderCtx.getFunctions();
    526 
    527 	const int				width				= viewport.z();
    528 	const int				height				= viewport.w();
    529 	const deInt32			defaultFramebuffer	= m_renderCtx.getDefaultFramebuffer();
    530 
    531 	DE_UNREF(program);
    532 
    533 	// blit to default framebuffer
    534 	gl.bindFramebuffer(GL_READ_FRAMEBUFFER, **m_fbo);
    535 	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFramebuffer);
    536 
    537 	gl.blitFramebuffer(0, 0, SIZE, SIZE, viewport.x(), viewport.y(), viewport.x() + width, viewport.y() + height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
    538 
    539 	gl.bindFramebuffer(GL_READ_FRAMEBUFFER, defaultFramebuffer);
    540 }
    541 
    542 struct BufferFmtDesc
    543 {
    544 	tcu::TextureFormat	texFmt;
    545 	GLenum				colorFmt;
    546 };
    547 
    548 struct Color
    549 {
    550 	enum Type {FLOAT, INT, UINT};
    551 
    552 	Type type;
    553 
    554 	union
    555 	{
    556 		float		f[4];
    557 		deInt32		i[4];
    558 		deUint32	u[4];
    559 	};
    560 
    561 	Color(const float f_[4])    : type(FLOAT) { f[0] = f_[0]; f[1] = f_[1]; f[2] = f_[2]; f[3] = f_[3]; }
    562 	Color(const deInt32 i_[4])  : type(INT)   { i[0] = i_[0]; i[1] = i_[1]; i[2] = i_[2]; i[3] = i_[3]; }
    563 	Color(const deUint32 u_[4]) : type(UINT)  { u[0] = u_[0]; u[1] = u_[1]; u[2] = u_[2]; u[3] = u_[3]; }
    564 };
    565 
    566 class FramebufferClearCase : public tcu::TestCase
    567 {
    568 public:
    569 							FramebufferClearCase	(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, ClearType clearType);
    570 	virtual					~FramebufferClearCase	(void) {}
    571 
    572 	virtual IterateResult	iterate					(void);
    573 
    574 private:
    575 	static void				clearBuffers			(const glw::Functions& gl, Color color, float depth, int stencil);
    576 	static Color			getBaseColor			(const BufferFmtDesc& bufferFmt);
    577 	static Color			getMainColor			(const BufferFmtDesc& bufferFmt);
    578 	static BufferFmtDesc	getBufferFormat			(ClearType type);
    579 
    580 	virtual void			render					(GLuint program) const;
    581 
    582 	glu::RenderContext&		m_renderCtx;
    583 	const ClearType			m_clearType;
    584 };
    585 
    586 FramebufferClearCase::FramebufferClearCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, ClearType clearType)
    587 	: tcu::TestCase	(testCtx, name, desc)
    588 	, m_renderCtx	(renderCtx)
    589 	, m_clearType	(clearType)
    590 {
    591 }
    592 
    593 void FramebufferClearCase::clearBuffers (const glw::Functions& gl, Color color, float depth, int stencil)
    594 {
    595 	switch(color.type)
    596 	{
    597 		case Color::FLOAT:	gl.clearBufferfv (GL_COLOR, 0, color.f); break;
    598 		case Color::INT:	gl.clearBufferiv (GL_COLOR, 0, color.i); break;
    599 		case Color::UINT:	gl.clearBufferuiv(GL_COLOR, 0, color.u); break;
    600 		default:
    601 			DE_ASSERT(false);
    602 	}
    603 
    604 	gl.clearBufferfv(GL_DEPTH, 0, &depth);
    605 	gl.clearBufferiv(GL_STENCIL, 0, &stencil);
    606 }
    607 
    608 FramebufferClearCase::IterateResult FramebufferClearCase::iterate (void)
    609 {
    610 	TestLog&					log				= m_testCtx.getLog();
    611 	const glw::Functions&		gl				= m_renderCtx.getFunctions();
    612 	const glu::ShaderProgram	shader			(m_renderCtx, genShaders(glu::getContextTypeGLSLVersion(m_renderCtx.getType())));
    613 
    614 	const glu::Framebuffer		fbo				(gl);
    615 	const glu::Renderbuffer		colorbuf		(gl);
    616 	const glu::Renderbuffer		depthbuf		(gl);
    617 
    618 	const BufferFmtDesc			bufferFmt		= getBufferFormat(m_clearType);
    619 	const Color					baseColor		= getBaseColor(bufferFmt);
    620 
    621 	const int					width			= 64;
    622 	const int					height			= 64;
    623 
    624 	const IVec4					scissorArea		(8, 8, 48, 48);
    625 
    626 	vector<deUint8>				refData			(width*height*bufferFmt.texFmt.getPixelSize());
    627 	vector<deUint8>				resData			(width*height*bufferFmt.texFmt.getPixelSize());
    628 
    629 	tcu::PixelBufferAccess		refAccess		(bufferFmt.texFmt, width, height, 1, &refData[0]);
    630 	tcu::PixelBufferAccess		resAccess		(bufferFmt.texFmt, width, height, 1, &resData[0]);
    631 
    632 	if (!shader.isOk())
    633 	{
    634 		log << shader;
    635 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader compile/link failed");
    636 		return STOP;
    637 	}
    638 
    639 	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
    640 	gl.bindFramebuffer(GL_READ_FRAMEBUFFER, *fbo);
    641 
    642 	// Color
    643 	gl.bindRenderbuffer(GL_RENDERBUFFER, *colorbuf);
    644 	gl.renderbufferStorage(GL_RENDERBUFFER, bufferFmt.colorFmt, width, height);
    645 	gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorbuf);
    646 
    647 	// Depth/stencil
    648 	gl.bindRenderbuffer(GL_RENDERBUFFER, *depthbuf);
    649 	gl.renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
    650 	gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, *depthbuf);
    651 
    652 	log << TestLog::Message << "Scissor area is " << scissorArea << TestLog::EndMessage;
    653 
    654 	// Render reference
    655 	{
    656 		log << TestLog::Message << "Rendering reference (scissors disabled)" << TestLog::EndMessage;
    657 
    658 		gl.useProgram(shader.getProgram());
    659 		gl.viewport(0, 0, width, height);
    660 
    661 		gl.disable(GL_DEPTH_TEST);
    662 		gl.disable(GL_STENCIL_TEST);
    663 		gl.disable(GL_SCISSOR_TEST);
    664 
    665 		clearBuffers(gl, baseColor, 1.0f, 0);
    666 
    667 		render(shader.getProgram());
    668 
    669 		glu::readPixels(m_renderCtx, 0, 0, refAccess);
    670 		GLU_CHECK_ERROR(gl.getError());
    671 	}
    672 
    673 	// Render result
    674 	{
    675 		log << TestLog::Message << "Rendering result (scissors enabled)" << TestLog::EndMessage;
    676 
    677 		gl.useProgram(shader.getProgram());
    678 		gl.viewport(0, 0, width, height);
    679 
    680 		gl.disable(GL_DEPTH_TEST);
    681 		gl.disable(GL_STENCIL_TEST);
    682 		gl.disable(GL_SCISSOR_TEST);
    683 
    684 		clearBuffers(gl, baseColor, 1.0f, 0);
    685 
    686 		gl.enable(GL_SCISSOR_TEST);
    687 		gl.scissor(scissorArea.x(), scissorArea.y(), scissorArea.z(), scissorArea.w());
    688 
    689 		render(shader.getProgram());
    690 
    691 		glu::readPixels(m_renderCtx, 0, 0, resAccess);
    692 		GLU_CHECK_ERROR(gl.getError());
    693 	}
    694 
    695 	{
    696 		bool resultOk = false;
    697 
    698 		switch (baseColor.type)
    699 		{
    700 			case Color::FLOAT:
    701 				clearEdges(refAccess, Vec4(baseColor.f[0], baseColor.f[1], baseColor.f[2], baseColor.f[3]), scissorArea);
    702 				resultOk = tcu::floatThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, Vec4(0.02f, 0.02f, 0.02f, 0.02f), tcu::COMPARE_LOG_RESULT);
    703 				break;
    704 
    705 			case Color::INT:
    706 				clearEdges(refAccess, IVec4(baseColor.i[0], baseColor.i[1], baseColor.i[2], baseColor.i[3]), scissorArea);
    707 				resultOk = tcu::intThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, UVec4(2, 2, 2, 2), tcu::COMPARE_LOG_RESULT);
    708 				break;
    709 
    710 			case Color::UINT:
    711 				clearEdges(refAccess, UVec4(baseColor.u[0], baseColor.u[1], baseColor.u[2], baseColor.u[3]), scissorArea);
    712 				resultOk = tcu::intThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, UVec4(2, 2, 2, 2), tcu::COMPARE_LOG_RESULT);
    713 				break;
    714 		}
    715 
    716 		if (resultOk)
    717 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    718 		else
    719 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
    720 	}
    721 
    722 	return STOP;
    723 }
    724 
    725 Color FramebufferClearCase::getBaseColor (const BufferFmtDesc& bufferFmt)
    726 {
    727 	const float		f[4] = {0.125f, 0.25f, 0.5f, 1.0f};
    728 	const deInt32	i[4] = {0, 0, 0, 0};
    729 	const deUint32	u[4] = {0, 0, 0, 0};
    730 
    731 	switch(bufferFmt.colorFmt)
    732 	{
    733 		case GL_RGBA8:		return Color(f);
    734 		case GL_RGBA8I:		return Color(i);
    735 		case GL_RGBA8UI:	return Color(u);
    736 		default:
    737 			DE_ASSERT(false);
    738 	}
    739 
    740 	return Color(f);
    741 }
    742 
    743 Color FramebufferClearCase::getMainColor (const BufferFmtDesc& bufferFmt)
    744 {
    745 	const float		f[4] = {1.0f, 1.0f, 0.5f, 1.0f};
    746 	const deInt32	i[4] = {127, -127, 0, 127};
    747 	const deUint32	u[4] = {255, 255, 0, 255};
    748 
    749 	switch(bufferFmt.colorFmt)
    750 	{
    751 		case GL_RGBA8:		return Color(f);
    752 		case GL_RGBA8I:		return Color(i);
    753 		case GL_RGBA8UI:	return Color(u);
    754 		default:
    755 			DE_ASSERT(false);
    756 	}
    757 
    758 	return Color(f);
    759 }
    760 
    761 BufferFmtDesc FramebufferClearCase::getBufferFormat (ClearType type)
    762 {
    763 	BufferFmtDesc retval;
    764 
    765 	switch (type)
    766 	{
    767 		case CLEAR_COLOR_FLOAT:
    768 			retval.colorFmt	= GL_RGBA16F;
    769 			retval.texFmt	= tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::HALF_FLOAT);
    770 			DE_ASSERT(!"Floating point clear not implemented");// \todo [2014-1-23 otto] pixel read format & type, nothing guaranteed, need extension...
    771 			break;
    772 
    773 		case CLEAR_COLOR_INT:
    774 			retval.colorFmt	= GL_RGBA8I;
    775 			retval.texFmt	= tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32);
    776 			break;
    777 
    778 		case CLEAR_COLOR_UINT:
    779 			retval.colorFmt	= GL_RGBA8UI;
    780 			retval.texFmt	= tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32);
    781 			break;
    782 
    783 		default:
    784 			retval.colorFmt = GL_RGBA8;
    785 			retval.texFmt	= tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
    786 			break;
    787 	}
    788 
    789 	return retval;
    790 }
    791 
    792 void FramebufferClearCase::render (GLuint program) const
    793 {
    794 	const glw::Functions&	gl					= m_renderCtx.getFunctions();
    795 
    796 	const BufferFmtDesc		bufferFmt			= getBufferFormat(m_clearType);
    797 	const Color				clearColor			= getMainColor(bufferFmt);
    798 
    799 	const int				clearStencil		= 123;
    800 	const float				clearDepth			= 0.5f;
    801 
    802 	switch (m_clearType)
    803 	{
    804 		case CLEAR_COLOR_FIXED:		gl.clearBufferfv (GL_COLOR, 0, clearColor.f);						break;
    805 		case CLEAR_COLOR_FLOAT:		gl.clearBufferfv (GL_COLOR, 0, clearColor.f);						break;
    806 		case CLEAR_COLOR_INT:		gl.clearBufferiv (GL_COLOR, 0, clearColor.i);						break;
    807 		case CLEAR_COLOR_UINT:		gl.clearBufferuiv(GL_COLOR, 0, clearColor.u);						break;
    808 		case CLEAR_DEPTH:			gl.clearBufferfv (GL_DEPTH, 0, &clearDepth);						break;
    809 		case CLEAR_STENCIL:			gl.clearBufferiv (GL_STENCIL, 0, &clearStencil);					break;
    810 		case CLEAR_DEPTH_STENCIL:	gl.clearBufferfi (GL_DEPTH_STENCIL, 0, clearDepth, clearStencil);	break;
    811 
    812 		default:
    813 			DE_ASSERT(false);
    814 	}
    815 
    816 	const bool useDepth		= (m_clearType == CLEAR_DEPTH   || m_clearType == CLEAR_DEPTH_STENCIL);
    817 	const bool useStencil	= (m_clearType == CLEAR_STENCIL || m_clearType == CLEAR_DEPTH_STENCIL);
    818 
    819 	// Render something to expose changes to depth/stencil buffer
    820 	if (useDepth || useStencil)
    821 	{
    822 		if (useDepth)
    823 			gl.enable(GL_DEPTH_TEST);
    824 
    825 		if (useStencil)
    826 			gl.enable(GL_STENCIL_TEST);
    827 
    828 		gl.stencilFunc(GL_EQUAL, clearStencil, ~0u);
    829 		gl.depthFunc(GL_GREATER);
    830 		gl.disable(GL_SCISSOR_TEST);
    831 
    832 		gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, clearColor.f);
    833 		drawQuad(gl, program, tcu::Vec3(-1.0f, -1.0f, 0.6f), tcu::Vec3(1.0f, 1.0f, 0.6f));
    834 	}
    835 }
    836 
    837 } // Anonymous
    838 
    839 namespace ScissorTestInternal
    840 {
    841 
    842 tcu::TestNode* createPrimitiveTest (tcu::TestContext&	testCtx,
    843 									glu::RenderContext&	renderCtx,
    844 									const char*			name,
    845 									const char*			desc,
    846 									const Vec4&			scissorArea,
    847 									const Vec4&			renderArea,
    848 									PrimitiveType		type,
    849 									int					primitiveCount)
    850 {
    851 	return new ScissorPrimitiveCase(testCtx, renderCtx, name, desc, scissorArea, renderArea, type, primitiveCount);
    852 }
    853 
    854 tcu::TestNode* createClearTest (tcu::TestContext&	testCtx,
    855 								glu::RenderContext&	renderCtx,
    856 								const char*			name,
    857 								const char*			desc,
    858 								const Vec4&			scissorArea,
    859 								deUint32			clearMode)
    860 {
    861 	return new ScissorClearCase(testCtx, renderCtx, name, desc, scissorArea, clearMode);
    862 }
    863 
    864 tcu::TestNode* createFramebufferClearTest (tcu::TestContext&	testCtx,
    865 										   glu::RenderContext&	renderCtx,
    866 										   const char*			name,
    867 										   const char*			desc,
    868 										   ClearType			clearType)
    869 {
    870 	return new FramebufferClearCase(testCtx, renderCtx, name, desc, clearType);
    871 }
    872 
    873 tcu::TestNode* createFramebufferBlitTest (tcu::TestContext&		testCtx,
    874 										  glu::RenderContext&	renderCtx,
    875 										  const char*			name,
    876 										  const char*			desc,
    877 										  const Vec4&			scissorArea)
    878 {
    879 	return new FramebufferBlitCase(testCtx, renderCtx, name, desc, scissorArea);
    880 }
    881 
    882 } // ScissorTestInternal
    883 } // Functional
    884 } // gls
    885 } // deqp
    886