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 
36 namespace deqp
37 {
38 namespace gles3
39 {
40 namespace Functional
41 {
42 
43 using std::string;
44 using tcu::TestLog;
45 using tcu::Vec2;
46 using tcu::Vec3;
47 using tcu::Vec4;
48 using tcu::IVec2;
49 using tcu::IVec3;
50 using tcu::IVec4;
51 using tcu::UVec4;
52 using namespace FboTestUtil;
53 
54 class BasicFboMultisampleCase : public FboTestCase
55 {
56 public:
BasicFboMultisampleCase(Context & context,const char * name,const char * desc,deUint32 colorFormat,deUint32 depthStencilFormat,const IVec2 & size,int numSamples)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 
66 protected:
preCheck(void)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 
render(tcu::Surface & dst)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*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 
colorCompare(const tcu::Surface & reference,const tcu::Surface & result)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 
compare(const tcu::Surface & reference,const tcu::Surface & result)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 
242 private:
243 	deUint32	m_colorFormat;
244 	deUint32	m_depthStencilFormat;
245 	IVec2		m_size;
246 	int			m_numSamples;
247 };
248 
FboMultisampleTests(Context & context)249 FboMultisampleTests::FboMultisampleTests (Context& context)
250 	: TestCaseGroup(context, "msaa", "Multisample FBO tests")
251 {
252 }
253 
~FboMultisampleTests(void)254 FboMultisampleTests::~FboMultisampleTests (void)
255 {
256 }
257 
init(void)258 void 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