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