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 multisample tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es3fFboMultisampleTests.hpp"
25#include "es3fFboTestCase.hpp"
26#include "es3fFboTestUtil.hpp"
27#include "gluTextureUtil.hpp"
28#include "tcuImageCompare.hpp"
29#include "tcuTextureUtil.hpp"
30#include "tcuTestLog.hpp"
31#include "deStringUtil.hpp"
32#include "deRandom.hpp"
33#include "sglrContextUtil.hpp"
34#include "glwEnums.hpp"
35
36namespace deqp
37{
38namespace gles3
39{
40namespace Functional
41{
42
43using std::string;
44using tcu::TestLog;
45using tcu::Vec2;
46using tcu::Vec3;
47using tcu::Vec4;
48using tcu::IVec2;
49using tcu::IVec3;
50using tcu::IVec4;
51using tcu::UVec4;
52using namespace FboTestUtil;
53
54class BasicFboMultisampleCase : public FboTestCase
55{
56public:
57	BasicFboMultisampleCase (Context& context, const char* name, const char* desc, deUint32 colorFormat, deUint32 depthStencilFormat, const IVec2& size, int numSamples)
58		: FboTestCase			(context, name, desc)
59		, m_colorFormat			(colorFormat)
60		, m_depthStencilFormat	(depthStencilFormat)
61		, m_size				(size)
62		, m_numSamples			(numSamples)
63	{
64	}
65
66protected:
67	void preCheck (void)
68	{
69		checkFormatSupport	(m_colorFormat);
70		checkSampleCount	(m_colorFormat, m_numSamples);
71
72		if (m_depthStencilFormat != GL_NONE)
73		{
74			checkFormatSupport	(m_depthStencilFormat);
75			checkSampleCount	(m_depthStencilFormat, m_numSamples);
76		}
77	}
78
79	void render (tcu::Surface& dst)
80	{
81		tcu::TextureFormat		colorFmt				= glu::mapGLInternalFormat(m_colorFormat);
82		tcu::TextureFormat		depthStencilFmt			= m_depthStencilFormat != GL_NONE ? glu::mapGLInternalFormat(m_depthStencilFormat) : tcu::TextureFormat();
83		tcu::TextureFormatInfo	colorFmtInfo			= tcu::getTextureFormatInfo(colorFmt);
84		bool					depth					= depthStencilFmt.order == tcu::TextureFormat::D || depthStencilFmt.order == tcu::TextureFormat::DS;
85		bool					stencil					= depthStencilFmt.order == tcu::TextureFormat::S || depthStencilFmt.order == tcu::TextureFormat::DS;
86		GradientShader			gradShader				(getFragmentOutputType(colorFmt));
87		FlatColorShader			flatShader				(getFragmentOutputType(colorFmt));
88		deUint32				gradShaderID			= getCurrentContext()->createProgram(&gradShader);
89		deUint32				flatShaderID			= getCurrentContext()->createProgram(&flatShader);
90		deUint32				msaaFbo					= 0;
91		deUint32				resolveFbo				= 0;
92		deUint32				msaaColorRbo			= 0;
93		deUint32				resolveColorRbo			= 0;
94		deUint32				msaaDepthStencilRbo		= 0;
95		deUint32				resolveDepthStencilRbo	= 0;
96
97		// Create framebuffers.
98		for (int ndx = 0; ndx < 2; ndx++)
99		{
100			deUint32&	fbo				= ndx ? resolveFbo				: msaaFbo;
101			deUint32&	colorRbo		= ndx ? resolveColorRbo			: msaaColorRbo;
102			deUint32&	depthStencilRbo	= ndx ? resolveDepthStencilRbo	: msaaDepthStencilRbo;
103			int			samples			= ndx ? 0						: m_numSamples;
104
105			glGenRenderbuffers(1, &colorRbo);
106			glBindRenderbuffer(GL_RENDERBUFFER, colorRbo);
107			glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, m_colorFormat, m_size.x(), m_size.y());
108
109			if (depth || stencil)
110			{
111				glGenRenderbuffers(1, &depthStencilRbo);
112				glBindRenderbuffer(GL_RENDERBUFFER, depthStencilRbo);
113				glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, m_depthStencilFormat, m_size.x(), m_size.y());
114			}
115
116			glGenFramebuffers(1, &fbo);
117			glBindFramebuffer(GL_FRAMEBUFFER, fbo);
118			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo);
119			if (depth)
120				glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo);
121			if (stencil)
122				glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo);
123
124			checkError();
125			checkFramebufferStatus(GL_FRAMEBUFFER);
126		}
127
128		glBindFramebuffer(GL_FRAMEBUFFER, msaaFbo);
129		glViewport(0, 0, m_size.x(), m_size.y());
130
131		// Clear depth and stencil buffers.
132		glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0);
133
134		// Fill MSAA fbo with gradient, depth = [-1..1]
135		glEnable(GL_DEPTH_TEST);
136		gradShader.setGradient(*getCurrentContext(), gradShaderID, colorFmtInfo.valueMin, colorFmtInfo.valueMax);
137		sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f));
138
139		// Render random-colored quads.
140		{
141			const int		numQuads	= 8;
142			de::Random		rnd			(9);
143
144			glDepthFunc(GL_ALWAYS);
145			glEnable(GL_STENCIL_TEST);
146			glStencilFunc(GL_ALWAYS, 0, 0xffu);
147			glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
148
149			for (int ndx = 0; ndx < numQuads; ndx++)
150			{
151				float	r		= rnd.getFloat();
152				float	g		= rnd.getFloat();
153				float	b		= rnd.getFloat();
154				float	a		= rnd.getFloat();
155				float	x0		= rnd.getFloat(-1.0f, 1.0f);
156				float	y0		= rnd.getFloat(-1.0f, 1.0f);
157				float	z0		= rnd.getFloat(-1.0f, 1.0f);
158				float	x1		= rnd.getFloat(-1.0f, 1.0f);
159				float	y1		= rnd.getFloat(-1.0f, 1.0f);
160				float	z1		= rnd.getFloat(-1.0f, 1.0f);
161
162				flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(r,g,b,a) * (colorFmtInfo.valueMax-colorFmtInfo.valueMin) + colorFmtInfo.valueMin);
163				sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(x0, y0, z0), Vec3(x1, y1, z1));
164			}
165		}
166
167		glDisable(GL_DEPTH_TEST);
168		glDisable(GL_STENCIL_TEST);
169		checkError();
170
171		// Resolve using glBlitFramebuffer().
172		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFbo);
173		glBlitFramebuffer(0, 0, m_size.x(), m_size.y(), 0, 0, m_size.x(), m_size.y(), GL_COLOR_BUFFER_BIT | (depth ? GL_DEPTH_BUFFER_BIT : 0) | (stencil ? GL_STENCIL_BUFFER_BIT : 0), GL_NEAREST);
174
175		glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFbo);
176
177		if (depth)
178		{
179			// Visualize depth.
180			const int	numSteps	= 8;
181			const float	step		= 2.0f / (float)numSteps;
182
183			glEnable(GL_DEPTH_TEST);
184			glDepthFunc(GL_LESS);
185			glDepthMask(GL_FALSE);
186			glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
187
188			for (int ndx = 0; ndx < numSteps; ndx++)
189			{
190				float d = -1.0f + step*(float)ndx;
191				float c = (float)ndx / (float)(numSteps-1);
192
193				flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 0.0f, c, 1.0f) * (colorFmtInfo.valueMax-colorFmtInfo.valueMin) + colorFmtInfo.valueMin);
194				sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, d), Vec3(1.0f, 1.0f, d));
195			}
196
197			glDisable(GL_DEPTH_TEST);
198		}
199
200		if (stencil)
201		{
202			// Visualize stencil.
203			const int	numSteps	= 4;
204			const int	step		= 1;
205
206			glEnable(GL_STENCIL_TEST);
207			glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
208			glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
209
210			for (int ndx = 0; ndx < numSteps; ndx++)
211			{
212				int		s	= step*ndx;
213				float	c	= (float)ndx / (float)(numSteps-1);
214
215				glStencilFunc(GL_EQUAL, s, 0xffu);
216
217				flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, c, 0.0f, 1.0f) * (colorFmtInfo.valueMax-colorFmtInfo.valueMin) + colorFmtInfo.valueMin);
218				sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
219			}
220
221			glDisable(GL_STENCIL_TEST);
222		}
223
224		readPixels(dst, 0, 0, m_size.x(), m_size.y(), colorFmt, colorFmtInfo.lookupScale, colorFmtInfo.lookupBias);
225	}
226
227	bool colorCompare (const tcu::Surface& reference, const tcu::Surface& result)
228	{
229		const tcu::RGBA threshold (tcu::max(getFormatThreshold(m_colorFormat), tcu::RGBA(12, 12, 12, 12)));
230
231		return tcu::bilinearCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference.getAccess(), result.getAccess(), threshold, tcu::COMPARE_LOG_RESULT);
232	}
233
234	bool compare (const tcu::Surface& reference, const tcu::Surface& result)
235	{
236		if (m_depthStencilFormat != GL_NONE)
237			return FboTestCase::compare(reference, result);
238		else
239			return colorCompare(reference, result);
240	}
241
242private:
243	deUint32	m_colorFormat;
244	deUint32	m_depthStencilFormat;
245	IVec2		m_size;
246	int			m_numSamples;
247};
248
249FboMultisampleTests::FboMultisampleTests (Context& context)
250	: TestCaseGroup(context, "msaa", "Multisample FBO tests")
251{
252}
253
254FboMultisampleTests::~FboMultisampleTests (void)
255{
256}
257
258void FboMultisampleTests::init (void)
259{
260	static const deUint32 colorFormats[] =
261	{
262		// RGBA formats
263		GL_RGBA8,
264		GL_SRGB8_ALPHA8,
265		GL_RGB10_A2,
266		GL_RGBA4,
267		GL_RGB5_A1,
268
269		// RGB formats
270		GL_RGB8,
271		GL_RGB565,
272
273		// RG formats
274		GL_RG8,
275
276		// R formats
277		GL_R8,
278
279		// GL_EXT_color_buffer_float
280		GL_RGBA32F,
281		GL_RGBA16F,
282		GL_R11F_G11F_B10F,
283		GL_RG32F,
284		GL_RG16F,
285		GL_R32F,
286		GL_R16F
287	};
288
289	static const deUint32 depthStencilFormats[] =
290	{
291		GL_DEPTH_COMPONENT32F,
292		GL_DEPTH_COMPONENT24,
293		GL_DEPTH_COMPONENT16,
294		GL_DEPTH32F_STENCIL8,
295		GL_DEPTH24_STENCIL8,
296		GL_STENCIL_INDEX8
297	};
298
299	static const int sampleCounts[] = { 2, 4, 8 };
300
301	for (int sampleCntNdx = 0; sampleCntNdx < DE_LENGTH_OF_ARRAY(sampleCounts); sampleCntNdx++)
302	{
303		int					samples				= sampleCounts[sampleCntNdx];
304		tcu::TestCaseGroup*	sampleCountGroup	= new tcu::TestCaseGroup(m_testCtx, (de::toString(samples) + "_samples").c_str(), "");
305		addChild(sampleCountGroup);
306
307		// Color formats.
308		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
309			sampleCountGroup->addChild(new BasicFboMultisampleCase(m_context, getFormatName(colorFormats[fmtNdx]), "", colorFormats[fmtNdx], GL_NONE, IVec2(119, 131), samples));
310
311		// Depth/stencil formats.
312		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(depthStencilFormats); fmtNdx++)
313			sampleCountGroup->addChild(new BasicFboMultisampleCase(m_context, getFormatName(depthStencilFormats[fmtNdx]), "", GL_RGBA8, depthStencilFormats[fmtNdx], IVec2(119, 131), samples));
314	}
315}
316
317} // Functional
318} // gles3
319} // deqp
320