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 "es3fApiCase.hpp"
25 #include "es3fFboMultisampleTests.hpp"
26 #include "es3fFboTestCase.hpp"
27 #include "es3fFboTestUtil.hpp"
28 #include "gluTextureUtil.hpp"
29 #include "tcuImageCompare.hpp"
30 #include "tcuTextureUtil.hpp"
31 #include "tcuTestLog.hpp"
32 #include "deStringUtil.hpp"
33 #include "deRandom.hpp"
34 #include "sglrContextUtil.hpp"
35 #include "glwEnums.hpp"
36 
37 namespace deqp
38 {
39 namespace gles3
40 {
41 namespace Functional
42 {
43 
44 using std::string;
45 using tcu::TestLog;
46 using tcu::Vec2;
47 using tcu::Vec3;
48 using tcu::Vec4;
49 using tcu::IVec2;
50 using tcu::IVec3;
51 using tcu::IVec4;
52 using tcu::UVec4;
53 using namespace FboTestUtil;
54 
55 class BasicFboMultisampleCase : public FboTestCase
56 {
57 public:
BasicFboMultisampleCase(Context & context,const char * name,const char * desc,deUint32 colorFormat,deUint32 depthStencilFormat,const IVec2 & size,int numSamples)58 	BasicFboMultisampleCase (Context& context, const char* name, const char* desc, deUint32 colorFormat, deUint32 depthStencilFormat, const IVec2& size, int numSamples)
59 		: FboTestCase			(context, name, desc)
60 		, m_colorFormat			(colorFormat)
61 		, m_depthStencilFormat	(depthStencilFormat)
62 		, m_size				(size)
63 		, m_numSamples			(numSamples)
64 	{
65 	}
66 
67 protected:
preCheck(void)68 	void preCheck (void)
69 	{
70 		checkFormatSupport	(m_colorFormat);
71 		checkSampleCount	(m_colorFormat, m_numSamples);
72 
73 		if (m_depthStencilFormat != GL_NONE)
74 		{
75 			checkFormatSupport	(m_depthStencilFormat);
76 			checkSampleCount	(m_depthStencilFormat, m_numSamples);
77 		}
78 	}
79 
render(tcu::Surface & dst)80 	void render (tcu::Surface& dst)
81 	{
82 		tcu::TextureFormat		colorFmt				= glu::mapGLInternalFormat(m_colorFormat);
83 		tcu::TextureFormat		depthStencilFmt			= m_depthStencilFormat != GL_NONE ? glu::mapGLInternalFormat(m_depthStencilFormat) : tcu::TextureFormat();
84 		tcu::TextureFormatInfo	colorFmtInfo			= tcu::getTextureFormatInfo(colorFmt);
85 		bool					depth					= depthStencilFmt.order == tcu::TextureFormat::D || depthStencilFmt.order == tcu::TextureFormat::DS;
86 		bool					stencil					= depthStencilFmt.order == tcu::TextureFormat::S || depthStencilFmt.order == tcu::TextureFormat::DS;
87 		GradientShader			gradShader				(getFragmentOutputType(colorFmt));
88 		FlatColorShader			flatShader				(getFragmentOutputType(colorFmt));
89 		deUint32				gradShaderID			= getCurrentContext()->createProgram(&gradShader);
90 		deUint32				flatShaderID			= getCurrentContext()->createProgram(&flatShader);
91 		deUint32				msaaFbo					= 0;
92 		deUint32				resolveFbo				= 0;
93 		deUint32				msaaColorRbo			= 0;
94 		deUint32				resolveColorRbo			= 0;
95 		deUint32				msaaDepthStencilRbo		= 0;
96 		deUint32				resolveDepthStencilRbo	= 0;
97 
98 		// Create framebuffers.
99 		for (int ndx = 0; ndx < 2; ndx++)
100 		{
101 			deUint32&	fbo				= ndx ? resolveFbo				: msaaFbo;
102 			deUint32&	colorRbo		= ndx ? resolveColorRbo			: msaaColorRbo;
103 			deUint32&	depthStencilRbo	= ndx ? resolveDepthStencilRbo	: msaaDepthStencilRbo;
104 			int			samples			= ndx ? 0						: m_numSamples;
105 
106 			glGenRenderbuffers(1, &colorRbo);
107 			glBindRenderbuffer(GL_RENDERBUFFER, colorRbo);
108 			glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, m_colorFormat, m_size.x(), m_size.y());
109 
110 			if (depth || stencil)
111 			{
112 				glGenRenderbuffers(1, &depthStencilRbo);
113 				glBindRenderbuffer(GL_RENDERBUFFER, depthStencilRbo);
114 				glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, m_depthStencilFormat, m_size.x(), m_size.y());
115 			}
116 
117 			glGenFramebuffers(1, &fbo);
118 			glBindFramebuffer(GL_FRAMEBUFFER, fbo);
119 			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo);
120 			if (depth)
121 				glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo);
122 			if (stencil)
123 				glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo);
124 
125 			checkError();
126 			checkFramebufferStatus(GL_FRAMEBUFFER);
127 		}
128 
129 		glBindFramebuffer(GL_FRAMEBUFFER, msaaFbo);
130 		glViewport(0, 0, m_size.x(), m_size.y());
131 
132 		// Clear depth and stencil buffers.
133 		glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0);
134 
135 		// Fill MSAA fbo with gradient, depth = [-1..1]
136 		glEnable(GL_DEPTH_TEST);
137 		gradShader.setGradient(*getCurrentContext(), gradShaderID, colorFmtInfo.valueMin, colorFmtInfo.valueMax);
138 		sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f));
139 
140 		// Render random-colored quads.
141 		{
142 			const int		numQuads	= 8;
143 			de::Random		rnd			(9);
144 
145 			glDepthFunc(GL_ALWAYS);
146 			glEnable(GL_STENCIL_TEST);
147 			glStencilFunc(GL_ALWAYS, 0, 0xffu);
148 			glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
149 
150 			for (int ndx = 0; ndx < numQuads; ndx++)
151 			{
152 				float	r		= rnd.getFloat();
153 				float	g		= rnd.getFloat();
154 				float	b		= rnd.getFloat();
155 				float	a		= rnd.getFloat();
156 				float	x0		= rnd.getFloat(-1.0f, 1.0f);
157 				float	y0		= rnd.getFloat(-1.0f, 1.0f);
158 				float	z0		= rnd.getFloat(-1.0f, 1.0f);
159 				float	x1		= rnd.getFloat(-1.0f, 1.0f);
160 				float	y1		= rnd.getFloat(-1.0f, 1.0f);
161 				float	z1		= rnd.getFloat(-1.0f, 1.0f);
162 
163 				flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(r,g,b,a) * (colorFmtInfo.valueMax-colorFmtInfo.valueMin) + colorFmtInfo.valueMin);
164 				sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(x0, y0, z0), Vec3(x1, y1, z1));
165 			}
166 		}
167 
168 		glDisable(GL_DEPTH_TEST);
169 		glDisable(GL_STENCIL_TEST);
170 		checkError();
171 
172 		// Resolve using glBlitFramebuffer().
173 		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFbo);
174 		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);
175 
176 		glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFbo);
177 
178 		if (depth)
179 		{
180 			// Visualize depth.
181 			const int	numSteps	= 8;
182 			const float	step		= 2.0f / (float)numSteps;
183 
184 			glEnable(GL_DEPTH_TEST);
185 			glDepthFunc(GL_LESS);
186 			glDepthMask(GL_FALSE);
187 			glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
188 
189 			for (int ndx = 0; ndx < numSteps; ndx++)
190 			{
191 				float d = -1.0f + step*(float)ndx;
192 				float c = (float)ndx / (float)(numSteps-1);
193 
194 				flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 0.0f, c, 1.0f) * (colorFmtInfo.valueMax-colorFmtInfo.valueMin) + colorFmtInfo.valueMin);
195 				sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, d), Vec3(1.0f, 1.0f, d));
196 			}
197 
198 			glDisable(GL_DEPTH_TEST);
199 		}
200 
201 		if (stencil)
202 		{
203 			// Visualize stencil.
204 			const int	numSteps	= 4;
205 			const int	step		= 1;
206 
207 			glEnable(GL_STENCIL_TEST);
208 			glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
209 			glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
210 
211 			for (int ndx = 0; ndx < numSteps; ndx++)
212 			{
213 				int		s	= step*ndx;
214 				float	c	= (float)ndx / (float)(numSteps-1);
215 
216 				glStencilFunc(GL_EQUAL, s, 0xffu);
217 
218 				flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, c, 0.0f, 1.0f) * (colorFmtInfo.valueMax-colorFmtInfo.valueMin) + colorFmtInfo.valueMin);
219 				sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
220 			}
221 
222 			glDisable(GL_STENCIL_TEST);
223 		}
224 
225 		readPixels(dst, 0, 0, m_size.x(), m_size.y(), colorFmt, colorFmtInfo.lookupScale, colorFmtInfo.lookupBias);
226 	}
227 
colorCompare(const tcu::Surface & reference,const tcu::Surface & result)228 	bool colorCompare (const tcu::Surface& reference, const tcu::Surface& result)
229 	{
230 		const tcu::RGBA threshold (tcu::max(getFormatThreshold(m_colorFormat), tcu::RGBA(12, 12, 12, 12)));
231 
232 		return tcu::bilinearCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference.getAccess(), result.getAccess(), threshold, tcu::COMPARE_LOG_RESULT);
233 	}
234 
compare(const tcu::Surface & reference,const tcu::Surface & result)235 	bool compare (const tcu::Surface& reference, const tcu::Surface& result)
236 	{
237 		if (m_depthStencilFormat != GL_NONE)
238 			return FboTestCase::compare(reference, result);
239 		else
240 			return colorCompare(reference, result);
241 	}
242 
243 private:
244 	deUint32	m_colorFormat;
245 	deUint32	m_depthStencilFormat;
246 	IVec2		m_size;
247 	int			m_numSamples;
248 };
249 
250 // Ported from WebGL [1], originally written to test a Qualcomm driver bug [2].
251 // [1] https://github.com/KhronosGroup/WebGL/blob/master/sdk/tests/conformance2/renderbuffers/multisampled-renderbuffer-initialization.html
252 // [2] http://crbug.com/696126
253 class RenderbufferResizeCase : public ApiCase
254 {
255 public:
RenderbufferResizeCase(Context & context,const char * name,const char * desc,bool multisampled1,bool multisampled2)256 	RenderbufferResizeCase (Context& context, const char* name, const char* desc, bool multisampled1, bool multisampled2)
257 		: ApiCase	(context, name, desc)
258 		, m_multisampled1(multisampled1)
259 		, m_multisampled2(multisampled2)
260 	{
261 	}
262 
263 protected:
test()264 	void test ()
265 	{
266 		glDisable(GL_DEPTH_TEST);
267 
268 		int maxSamples = 0;
269 		glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA8, GL_SAMPLES, 1, &maxSamples);
270 		deUint32 samp1 = m_multisampled1 ? maxSamples : 0;
271 		deUint32 samp2 = m_multisampled2 ? maxSamples : 0;
272 
273 		static const deUint32 W1 = 10, H1 = 10;
274 		static const deUint32 W2 = 40, H2 = 40;
275 
276 		// Set up non-multisampled buffer to blit to and read back from.
277 		deUint32 fboResolve = 0;
278 		deUint32 rboResolve = 0;
279 		{
280 			glGenFramebuffers(1, &fboResolve);
281 			glBindFramebuffer(GL_FRAMEBUFFER, fboResolve);
282 			glGenRenderbuffers(1, &rboResolve);
283 			glBindRenderbuffer(GL_RENDERBUFFER, rboResolve);
284 			glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, W2, H2);
285 			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboResolve);
286 			TCU_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
287 			glClearBufferfv(GL_COLOR, 0, Vec4(1.0f, 0.0f, 0.0f, 1.0f).getPtr());
288 		}
289 		expectError(GL_NO_ERROR);
290 
291 		// Set up multisampled buffer to test.
292 		deUint32 fboMultisampled = 0;
293 		deUint32 rboMultisampled = 0;
294 		{
295 			glGenFramebuffers(1, &fboMultisampled);
296 			glBindFramebuffer(GL_FRAMEBUFFER, fboMultisampled);
297 			glGenRenderbuffers(1, &rboMultisampled);
298 			glBindRenderbuffer(GL_RENDERBUFFER, rboMultisampled);
299 			// Allocate,
300 			glRenderbufferStorageMultisample(GL_RENDERBUFFER, samp1, GL_RGBA8, W1, H1);
301 			// attach,
302 			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboMultisampled);
303 			TCU_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
304 			glClearBufferfv(GL_COLOR, 0, Vec4(0.0f, 0.0f, 1.0f, 1.0f).getPtr());
305 			// and allocate again with different parameters.
306 			glRenderbufferStorageMultisample(GL_RENDERBUFFER, samp2, GL_RGBA8, W2, H2);
307 			TCU_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
308 			glClearBufferfv(GL_COLOR, 0, Vec4(0.0f, 1.0f, 0.0f, 1.0f).getPtr());
309 		}
310 		expectError(GL_NO_ERROR);
311 
312 		// This is a blit from the multisampled buffer to the non-multisampled buffer.
313 		glBindFramebuffer(GL_READ_FRAMEBUFFER, fboMultisampled);
314 		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboResolve);
315 		// Blit color from fboMultisampled (should be green) to fboResolve (should currently be red).
316 		glBlitFramebuffer(0, 0, W2, H2, 0, 0, W2, H2, GL_COLOR_BUFFER_BIT, GL_NEAREST);
317 		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
318 		expectError(GL_NO_ERROR);
319 
320 		// fboResolve should now be green.
321 		glBindFramebuffer(GL_READ_FRAMEBUFFER, fboResolve);
322 		deUint32 pixels[W2 * H2] = {};
323 		glReadPixels(0, 0, W2, H2, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
324 		expectError(GL_NO_ERROR);
325 
326 		const tcu::RGBA threshold (tcu::max(getFormatThreshold(GL_RGBA8), tcu::RGBA(12, 12, 12, 12)));
327 		for (deUint32 y = 0; y < H2; ++y)
328 		{
329 			for (deUint32 x = 0; x < W2; ++x)
330 			{
331 				tcu::RGBA color(pixels[y * W2 + x]);
332 				TCU_CHECK(compareThreshold(color, tcu::RGBA::green(), threshold));
333 			}
334 		}
335 	}
336 
337 private:
338 	bool m_multisampled1;
339 	bool m_multisampled2;
340 };
341 
FboMultisampleTests(Context & context)342 FboMultisampleTests::FboMultisampleTests (Context& context)
343 	: TestCaseGroup(context, "msaa", "Multisample FBO tests")
344 {
345 }
346 
~FboMultisampleTests(void)347 FboMultisampleTests::~FboMultisampleTests (void)
348 {
349 }
350 
init(void)351 void FboMultisampleTests::init (void)
352 {
353 	static const deUint32 colorFormats[] =
354 	{
355 		// RGBA formats
356 		GL_RGBA8,
357 		GL_SRGB8_ALPHA8,
358 		GL_RGB10_A2,
359 		GL_RGBA4,
360 		GL_RGB5_A1,
361 
362 		// RGB formats
363 		GL_RGB8,
364 		GL_RGB565,
365 
366 		// RG formats
367 		GL_RG8,
368 
369 		// R formats
370 		GL_R8,
371 
372 		// GL_EXT_color_buffer_float
373 		GL_RGBA32F,
374 		GL_RGBA16F,
375 		GL_R11F_G11F_B10F,
376 		GL_RG32F,
377 		GL_RG16F,
378 		GL_R32F,
379 		GL_R16F
380 	};
381 
382 	static const deUint32 depthStencilFormats[] =
383 	{
384 		GL_DEPTH_COMPONENT32F,
385 		GL_DEPTH_COMPONENT24,
386 		GL_DEPTH_COMPONENT16,
387 		GL_DEPTH32F_STENCIL8,
388 		GL_DEPTH24_STENCIL8,
389 		GL_STENCIL_INDEX8
390 	};
391 
392 	static const int sampleCounts[] = { 2, 4, 8 };
393 
394 	for (int sampleCntNdx = 0; sampleCntNdx < DE_LENGTH_OF_ARRAY(sampleCounts); sampleCntNdx++)
395 	{
396 		int					samples				= sampleCounts[sampleCntNdx];
397 		tcu::TestCaseGroup*	sampleCountGroup	= new tcu::TestCaseGroup(m_testCtx, (de::toString(samples) + "_samples").c_str(), "");
398 		addChild(sampleCountGroup);
399 
400 		// Color formats.
401 		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
402 			sampleCountGroup->addChild(new BasicFboMultisampleCase(m_context, getFormatName(colorFormats[fmtNdx]), "", colorFormats[fmtNdx], GL_NONE, IVec2(119, 131), samples));
403 
404 		// Depth/stencil formats.
405 		for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(depthStencilFormats); fmtNdx++)
406 			sampleCountGroup->addChild(new BasicFboMultisampleCase(m_context, getFormatName(depthStencilFormats[fmtNdx]), "", GL_RGBA8, depthStencilFormats[fmtNdx], IVec2(119, 131), samples));
407 	}
408 
409 	// .renderbuffer_resize
410 	{
411 		tcu::TestCaseGroup* group = new tcu::TestCaseGroup(m_testCtx, "renderbuffer_resize", "Multisample renderbuffer resize");
412 		addChild(group);
413 
414 		{
415 			group->addChild(new RenderbufferResizeCase(m_context, "nonms_to_nonms", "", false, false));
416 			group->addChild(new RenderbufferResizeCase(m_context, "nonms_to_ms", "", false, true));
417 			group->addChild(new RenderbufferResizeCase(m_context, "ms_to_nonms", "", true, false));
418 			group->addChild(new RenderbufferResizeCase(m_context, "ms_to_ms", "", true, true));
419 		}
420 	}
421 }
422 
423 } // Functional
424 } // gles3
425 } // deqp
426