1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief FBO stencilbuffer tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es3fFboStencilbufferTests.hpp"
25#include "es3fFboTestCase.hpp"
26#include "es3fFboTestUtil.hpp"
27#include "gluTextureUtil.hpp"
28#include "tcuTextureUtil.hpp"
29#include "sglrContextUtil.hpp"
30#include "glwEnums.hpp"
31
32namespace deqp
33{
34namespace gles3
35{
36namespace Functional
37{
38
39using std::string;
40using tcu::Vec2;
41using tcu::Vec3;
42using tcu::Vec4;
43using tcu::IVec2;
44using tcu::IVec3;
45using tcu::IVec4;
46using tcu::UVec4;
47using namespace FboTestUtil;
48
49class BasicFboStencilCase : public FboTestCase
50{
51public:
52	BasicFboStencilCase (Context& context, const char* name, const char* desc, deUint32 format, IVec2 size, bool useDepth)
53		: FboTestCase	(context, name, desc)
54		, m_format		(format)
55		, m_size		(size)
56		, m_useDepth	(useDepth)
57	{
58	}
59
60protected:
61	void preCheck (void)
62	{
63		checkFormatSupport(m_format);
64	}
65
66	void render (tcu::Surface& dst)
67	{
68		const deUint32			colorFormat		= GL_RGBA8;
69
70		GradientShader			gradShader		(glu::TYPE_FLOAT_VEC4);
71		FlatColorShader			flatShader		(glu::TYPE_FLOAT_VEC4);
72		deUint32				flatShaderID	= getCurrentContext()->createProgram(&flatShader);
73		deUint32				gradShaderID	= getCurrentContext()->createProgram(&gradShader);
74
75		deUint32				fbo				= 0;
76		deUint32				colorRbo		= 0;
77		deUint32				depthStencilRbo	= 0;
78
79		// Colorbuffer.
80		glGenRenderbuffers(1, &colorRbo);
81		glBindRenderbuffer(GL_RENDERBUFFER, colorRbo);
82		glRenderbufferStorage(GL_RENDERBUFFER, colorFormat, m_size.x(), m_size.y());
83
84		// Stencil (and depth) buffer.
85		glGenRenderbuffers(1, &depthStencilRbo);
86		glBindRenderbuffer(GL_RENDERBUFFER, depthStencilRbo);
87		glRenderbufferStorage(GL_RENDERBUFFER, m_format, m_size.x(), m_size.y());
88
89		// Framebuffer.
90		glGenFramebuffers(1, &fbo);
91		glBindFramebuffer(GL_FRAMEBUFFER, fbo);
92		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo);
93		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo);
94		if (m_useDepth)
95			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo);
96		checkError();
97		checkFramebufferStatus(GL_FRAMEBUFFER);
98
99		glViewport(0, 0, m_size.x(), m_size.y());
100
101		// Clear framebuffer.
102		glClearBufferfv(GL_COLOR, 0, Vec4(0.0f).getPtr());
103		glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0);
104
105		// Render intersecting quads - increment stencil on depth pass
106		glEnable(GL_DEPTH_TEST);
107		glEnable(GL_STENCIL_TEST);
108		glStencilFunc(GL_ALWAYS, 0, 0xffu);
109		glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
110
111		flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(1.0f, 0.0f, 0.0f, 1.0f));
112		sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f,  0.0f), Vec3(+1.0f, +1.0f,  0.0f));
113
114		gradShader.setGradient(*getCurrentContext(), gradShaderID, Vec4(0.0f), Vec4(1.0f));
115		sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(+1.0f, +1.0f, +1.0f));
116
117		glDisable(GL_DEPTH_TEST);
118
119		// Draw quad with stencil test (stencil == 1 or 2 depending on depth) - decrement on stencil failure
120		glStencilFunc(GL_EQUAL, m_useDepth ? 2 : 1, 0xffu);
121		glStencilOp(GL_DECR, GL_KEEP, GL_KEEP);
122
123		flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0));
124		sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-0.5f, -0.5f, 0.0f), Vec3(+0.5f, +0.5f, 0.0f));
125
126		// Draw quad with stencil test where stencil > 1 or 2 depending on depth buffer
127		glStencilFunc(GL_GREATER, m_useDepth ? 1 : 2, 0xffu);
128
129		flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 0.0f, 1.0f, 1.0f));
130		sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
131
132		readPixels(dst, 0, 0, m_size.x(), m_size.y(), glu::mapGLInternalFormat(colorFormat), Vec4(1.0f), Vec4(0.0f));
133	}
134
135private:
136	deUint32	m_format;
137	IVec2		m_size;
138	bool		m_useDepth;
139};
140
141class DepthStencilAttachCase : public FboTestCase
142{
143public:
144	DepthStencilAttachCase (Context& context, const char* name, const char* desc, deUint32 attachDepth, deUint32 attachStencil)
145		: FboTestCase		(context, name, desc)
146		, m_attachDepth		(attachDepth)
147		, m_attachStencil	(attachStencil)
148	{
149		DE_ASSERT(m_attachDepth == GL_DEPTH_ATTACHMENT || m_attachDepth == GL_DEPTH_STENCIL_ATTACHMENT || m_attachDepth == GL_NONE);
150		DE_ASSERT(m_attachStencil == GL_STENCIL_ATTACHMENT || m_attachStencil == GL_NONE);
151		DE_ASSERT(m_attachDepth != GL_DEPTH_STENCIL || m_attachStencil == GL_NONE);
152	}
153
154protected:
155	void render (tcu::Surface& dst)
156	{
157		const deUint32			colorFormat			= GL_RGBA8;
158		const deUint32			depthStencilFormat	= GL_DEPTH24_STENCIL8;
159		const int				width				= 128;
160		const int				height				= 128;
161		const bool				hasDepth			= (m_attachDepth == GL_DEPTH_STENCIL || m_attachDepth == GL_DEPTH_ATTACHMENT);
162//		const bool				hasStencil			= (m_attachDepth == GL_DEPTH_STENCIL || m_attachStencil == GL_DEPTH_STENCIL_ATTACHMENT);
163
164		GradientShader			gradShader			(glu::TYPE_FLOAT_VEC4);
165		FlatColorShader			flatShader			(glu::TYPE_FLOAT_VEC4);
166		deUint32				flatShaderID		= getCurrentContext()->createProgram(&flatShader);
167		deUint32				gradShaderID		= getCurrentContext()->createProgram(&gradShader);
168
169		deUint32				fbo					= 0;
170		deUint32				colorRbo			= 0;
171		deUint32				depthStencilRbo		= 0;
172
173		// Colorbuffer.
174		glGenRenderbuffers(1, &colorRbo);
175		glBindRenderbuffer(GL_RENDERBUFFER, colorRbo);
176		glRenderbufferStorage(GL_RENDERBUFFER, colorFormat, width, height);
177
178		// Depth-stencil buffer.
179		glGenRenderbuffers(1, &depthStencilRbo);
180		glBindRenderbuffer(GL_RENDERBUFFER, depthStencilRbo);
181		glRenderbufferStorage(GL_RENDERBUFFER, depthStencilFormat, width, height);
182
183		// Framebuffer.
184		glGenFramebuffers(1, &fbo);
185		glBindFramebuffer(GL_FRAMEBUFFER, fbo);
186		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo);
187
188		if (m_attachDepth != GL_NONE)
189			glFramebufferRenderbuffer(GL_FRAMEBUFFER, m_attachDepth, GL_RENDERBUFFER, depthStencilRbo);
190		if (m_attachStencil != GL_NONE)
191			glFramebufferRenderbuffer(GL_FRAMEBUFFER, m_attachStencil, GL_RENDERBUFFER, depthStencilRbo);
192
193		checkError();
194		checkFramebufferStatus(GL_FRAMEBUFFER);
195
196		glViewport(0, 0, width, height);
197
198		// Clear framebuffer.
199		glClearBufferfv(GL_COLOR, 0, Vec4(0.0f).getPtr());
200		glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0);
201
202		// Render intersecting quads - increment stencil on depth pass
203		glEnable(GL_DEPTH_TEST);
204		glEnable(GL_STENCIL_TEST);
205		glStencilFunc(GL_ALWAYS, 0, 0xffu);
206		glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
207
208		flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(1.0f, 0.0f, 0.0f, 1.0f));
209		sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f,  0.0f), Vec3(+1.0f, +1.0f,  0.0f));
210
211		gradShader.setGradient(*getCurrentContext(), gradShaderID, Vec4(0.0f), Vec4(1.0f));
212		sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(+1.0f, +1.0f, +1.0f));
213
214		glDisable(GL_DEPTH_TEST);
215
216		// Draw quad with stencil test (stencil == 1 or 2 depending on depth) - decrement on stencil failure
217		glStencilFunc(GL_EQUAL, hasDepth ? 2 : 1, 0xffu);
218		glStencilOp(GL_DECR, GL_KEEP, GL_KEEP);
219
220		flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0));
221		sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-0.5f, -0.5f, 0.0f), Vec3(+0.5f, +0.5f, 0.0f));
222
223		// Draw quad with stencil test where stencil > 1 or 2 depending on depth buffer
224		glStencilFunc(GL_GREATER, hasDepth ? 1 : 2, 0xffu);
225
226		flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 0.0f, 1.0f, 1.0f));
227		sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
228
229		readPixels(dst, 0, 0, width, height, glu::mapGLInternalFormat(colorFormat), Vec4(1.0f), Vec4(0.0f));
230	}
231
232private:
233	deUint32		m_attachDepth;
234	deUint32		m_attachStencil;
235};
236
237FboStencilTests::FboStencilTests (Context& context)
238	: TestCaseGroup(context, "stencil", "FBO Stencilbuffer tests")
239{
240}
241
242FboStencilTests::~FboStencilTests (void)
243{
244}
245
246void FboStencilTests::init (void)
247{
248	static const deUint32 stencilFormats[] =
249	{
250		GL_DEPTH32F_STENCIL8,
251		GL_DEPTH24_STENCIL8,
252		GL_STENCIL_INDEX8
253	};
254
255	// .basic
256	{
257		tcu::TestCaseGroup* basicGroup = new tcu::TestCaseGroup(m_testCtx, "basic", "Basic stencil tests");
258		addChild(basicGroup);
259
260		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(stencilFormats); fmtNdx++)
261		{
262			deUint32			format		= stencilFormats[fmtNdx];
263			tcu::TextureFormat	texFmt		= glu::mapGLInternalFormat(format);
264
265			basicGroup->addChild(new BasicFboStencilCase(m_context, getFormatName(format), "", format, IVec2(111, 132), false));
266
267			if (texFmt.order == tcu::TextureFormat::DS)
268				basicGroup->addChild(new BasicFboStencilCase(m_context, (string(getFormatName(format)) + "_depth").c_str(), "", format, IVec2(111, 132), true));
269		}
270	}
271
272	// .attach
273	{
274		tcu::TestCaseGroup* attachGroup = new tcu::TestCaseGroup(m_testCtx, "attach", "Attaching depth stencil");
275		addChild(attachGroup);
276
277		attachGroup->addChild(new DepthStencilAttachCase(m_context, "depth_only",				"Only depth part of depth-stencil RBO attached",			GL_DEPTH_ATTACHMENT,			GL_NONE));
278		attachGroup->addChild(new DepthStencilAttachCase(m_context, "stencil_only",				"Only stencil part of depth-stencil RBO attached",			GL_NONE,						GL_STENCIL_ATTACHMENT));
279		attachGroup->addChild(new DepthStencilAttachCase(m_context, "depth_stencil_separate",	"Depth and stencil attached separately",					GL_DEPTH_ATTACHMENT,			GL_STENCIL_ATTACHMENT));
280		attachGroup->addChild(new DepthStencilAttachCase(m_context, "depth_stencil_attachment",	"Depth and stencil attached with DEPTH_STENCIL_ATTACHMENT",	GL_DEPTH_STENCIL_ATTACHMENT,	GL_NONE));
281	}
282}
283
284} // Functional
285} // gles3
286} // deqp
287