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 
drawQuad(const glw::Functions & gl,deUint32 program,const Vec3 & p0,const Vec3 & p1)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 
drawPrimitives(const glw::Functions & gl,deUint32 program,const deUint32 type,const vector<float> & vertices,const vector<deUint16> & indices)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>
clearEdges(const tcu::PixelBufferAccess & access,const T & color,const IVec4 & scissorArea)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 
genShaders(glu::GLSLVersion version)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);
~ScissorCase(void)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 
ScissorCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,const Vec4 & scissorArea)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 
iterate(void)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);
~ScissorPrimitiveCase(void)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 
ScissorPrimitiveCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,const Vec4 & scissorArea,const Vec4 & renderArea,PrimitiveType type,int primitiveCount)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 
render(GLuint program,const IVec4 &) const322 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);
~ScissorClearCase(void)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 
ScissorClearCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,const Vec4 & scissorArea,deUint32 clearMode)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 
init(void)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 
render(GLuint program,const IVec4 &) const437 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);
~FramebufferBlitCase(void)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 
FramebufferBlitCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,const Vec4 & scissorArea)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 
init(void)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 
deinit(void)518 void FramebufferBlitCase::deinit (void)
519 {
520 	m_fbo.clear();
521 }
522 
render(GLuint program,const IVec4 & viewport) const523 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 
Colordeqp::gls::Functional::__anonfaabf09b0111::Color561 	Color(const float f_[4])    : type(FLOAT) { f[0] = f_[0]; f[1] = f_[1]; f[2] = f_[2]; f[3] = f_[3]; }
Colordeqp::gls::Functional::__anonfaabf09b0111::Color562 	Color(const deInt32 i_[4])  : type(INT)   { i[0] = i_[0]; i[1] = i_[1]; i[2] = i_[2]; i[3] = i_[3]; }
Colordeqp::gls::Functional::__anonfaabf09b0111::Color563 	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);
~FramebufferClearCase(void)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 
FramebufferClearCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,ClearType clearType)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 
clearBuffers(const glw::Functions & gl,Color color,float depth,int stencil)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 
iterate(void)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 
getBaseColor(const BufferFmtDesc & bufferFmt)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 
getMainColor(const BufferFmtDesc & bufferFmt)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 
getBufferFormat(ClearType type)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 
render(GLuint program) const792 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 
createPrimitiveTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,const Vec4 & scissorArea,const Vec4 & renderArea,PrimitiveType type,int primitiveCount)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 
createClearTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,const Vec4 & scissorArea,deUint32 clearMode)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 
createFramebufferClearTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,ClearType clearType)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 
createFramebufferBlitTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,const Vec4 & scissorArea)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