1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 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 Multisample shader render case
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fMultisampleShaderRenderCase.hpp"
25 #include "tcuRenderTarget.hpp"
26 #include "tcuSurface.hpp"
27 #include "tcuTestLog.hpp"
28 #include "tcuStringTemplate.hpp"
29 #include "gluShaderProgram.hpp"
30 #include "gluRenderContext.hpp"
31 #include "gluPixelTransfer.hpp"
32 #include "glwFunctions.hpp"
33 #include "glwEnums.hpp"
34 #include "deStringUtil.hpp"
35 
36 namespace deqp
37 {
38 namespace gles31
39 {
40 namespace Functional
41 {
42 namespace MultisampleShaderRenderUtil
43 {
44 using std::map;
45 using std::string;
46 namespace
47 {
48 
49 static const char* const s_vertexSource =	"${GLSL_VERSION_DECL}\n"
50 											"in highp vec4 a_position;\n"
51 											"out highp vec4 v_position;\n"
52 											"void main (void)\n"
53 											"{\n"
54 											"	gl_Position = a_position;\n"
55 											"	v_position = a_position;\n"
56 											"}";
57 
58 } // anonymous
59 
QualityWarning(const std::string & message)60 QualityWarning::QualityWarning (const std::string& message)
61 	: tcu::Exception(message)
62 {
63 }
64 
MultisampleRenderCase(Context & context,const char * name,const char * desc,int numSamples,RenderTarget target,int renderSize,int flags)65 MultisampleRenderCase::MultisampleRenderCase (Context& context, const char* name, const char* desc, int numSamples, RenderTarget target, int renderSize, int flags)
66 	: TestCase						(context, name, desc)
67 	, m_numRequestedSamples			(numSamples)
68 	, m_renderTarget				(target)
69 	, m_renderSize					(renderSize)
70 	, m_perIterationShader			((flags & FLAG_PER_ITERATION_SHADER) != 0)
71 	, m_verifyTextureSampleBuffers	((flags & FLAG_VERIFY_MSAA_TEXTURE_SAMPLE_BUFFERS) != 0 && target == TARGET_TEXTURE)
72 	, m_numTargetSamples			(-1)
73 	, m_buffer						(0)
74 	, m_resolveBuffer				(0)
75 	, m_program						(DE_NULL)
76 	, m_fbo							(0)
77 	, m_fboTexture					(0)
78 	, m_textureSamplerProgram		(DE_NULL)
79 	, m_fboRbo						(0)
80 	, m_resolveFbo					(0)
81 	, m_resolveFboTexture			(0)
82 	, m_iteration					(0)
83 	, m_numIterations				(1)
84 	, m_renderMode					(0)
85 	, m_renderCount					(0)
86 	, m_renderVao					(0)
87 	, m_resolveVao					(0)
88 {
89 	DE_ASSERT(target < TARGET_LAST);
90 }
91 
~MultisampleRenderCase(void)92 MultisampleRenderCase::~MultisampleRenderCase (void)
93 {
94 	MultisampleRenderCase::deinit();
95 }
96 
init(void)97 void MultisampleRenderCase::init (void)
98 {
99 	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
100 	deInt32					queriedSampleCount	= -1;
101 	const bool				isES32				= glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
102 	map<string, string>		args;
103 	args["GLSL_VERSION_DECL"]					= isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
104 
105 	// requirements
106 
107 	switch (m_renderTarget)
108 	{
109 		case TARGET_DEFAULT:
110 		{
111 			if (m_context.getRenderTarget().getWidth() < m_renderSize || m_context.getRenderTarget().getHeight() < m_renderSize)
112 				throw tcu::NotSupportedError("Test requires render target with size " + de::toString(m_renderSize) + "x" + de::toString(m_renderSize) + " or greater");
113 			break;
114 		}
115 
116 		case TARGET_TEXTURE:
117 		{
118 			deInt32 maxTextureSamples = 0;
119 			gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, 1, &maxTextureSamples);
120 
121 			if (m_numRequestedSamples > maxTextureSamples)
122 				throw tcu::NotSupportedError("Sample count not supported");
123 			break;
124 		}
125 
126 		case TARGET_RENDERBUFFER:
127 		{
128 			deInt32 maxRboSamples = 0;
129 			gl.getInternalformativ(GL_RENDERBUFFER, GL_RGBA8, GL_SAMPLES, 1, &maxRboSamples);
130 
131 			if (m_numRequestedSamples > maxRboSamples)
132 				throw tcu::NotSupportedError("Sample count not supported");
133 			break;
134 		}
135 
136 		default:
137 			DE_ASSERT(false);
138 	}
139 
140 	// resources
141 
142 	{
143 		gl.genBuffers(1, &m_buffer);
144 		GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
145 
146 		setupRenderData();
147 		GLU_EXPECT_NO_ERROR(gl.getError(), "setup data");
148 
149 		gl.genVertexArrays(1, &m_renderVao);
150 		GLU_EXPECT_NO_ERROR(gl.getError(), "gen vao");
151 
152 		// buffer for MSAA texture resolving
153 		{
154 			static const tcu::Vec4 fullscreenQuad[] =
155 			{
156 				tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
157 				tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
158 				tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
159 				tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
160 			};
161 
162 			gl.genBuffers(1, &m_resolveBuffer);
163 			gl.bindBuffer(GL_ARRAY_BUFFER, m_resolveBuffer);
164 			gl.bufferData(GL_ARRAY_BUFFER, (int)sizeof(fullscreenQuad), fullscreenQuad, GL_STATIC_DRAW);
165 			GLU_EXPECT_NO_ERROR(gl.getError(), "setup data");
166 		}
167 	}
168 
169 	// msaa targets
170 
171 	if (m_renderTarget == TARGET_TEXTURE)
172 	{
173 		const deUint32 textureTarget = (m_numRequestedSamples == 0) ? (GL_TEXTURE_2D) : (GL_TEXTURE_2D_MULTISAMPLE);
174 
175 		gl.genVertexArrays(1, &m_resolveVao);
176 		GLU_EXPECT_NO_ERROR(gl.getError(), "gen vao");
177 
178 		gl.genTextures(1, &m_fboTexture);
179 		gl.bindTexture(textureTarget, m_fboTexture);
180 		if (m_numRequestedSamples == 0)
181 		{
182 			gl.texStorage2D(textureTarget, 1, GL_RGBA8, m_renderSize, m_renderSize);
183 			gl.texParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
184 			gl.texParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
185 		}
186 		else
187 			gl.texStorage2DMultisample(textureTarget, m_numRequestedSamples, GL_RGBA8, m_renderSize, m_renderSize, GL_FALSE);
188 		GLU_EXPECT_NO_ERROR(gl.getError(), "gen tex");
189 
190 		gl.genFramebuffers(1, &m_fbo);
191 		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
192 		gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureTarget, m_fboTexture, 0);
193 		GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
194 
195 		if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
196 			throw tcu::TestError("fbo not complete");
197 
198 		if (m_numRequestedSamples != 0)
199 		{
200 			// for shader
201 			gl.getTexLevelParameteriv(GL_TEXTURE_2D_MULTISAMPLE, 0, GL_TEXTURE_SAMPLES, &queriedSampleCount);
202 
203 			// logging
204 			m_testCtx.getLog() << tcu::TestLog::Message << "Asked for " << m_numRequestedSamples << " samples, got " << queriedSampleCount << " samples." << tcu::TestLog::EndMessage;
205 
206 			// sanity
207 			if (queriedSampleCount < m_numRequestedSamples)
208 				throw tcu::TestError("Got less texture samples than asked for");
209 		}
210 
211 		// texture sampler shader
212 		m_textureSamplerProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
213 			<< glu::VertexSource(tcu::StringTemplate(s_vertexSource).specialize(args))
214 			<< glu::FragmentSource(genMSSamplerSource(queriedSampleCount)));
215 		if (!m_textureSamplerProgram->isOk())
216 		{
217 			m_testCtx.getLog() << tcu::TestLog::Section("SamplerShader", "Sampler shader") << *m_textureSamplerProgram << tcu::TestLog::EndSection;
218 			throw tcu::TestError("could not build program");
219 		}
220 	}
221 	else if (m_renderTarget == TARGET_RENDERBUFFER)
222 	{
223 		gl.genRenderbuffers(1, &m_fboRbo);
224 		gl.bindRenderbuffer(GL_RENDERBUFFER, m_fboRbo);
225 		gl.renderbufferStorageMultisample(GL_RENDERBUFFER, m_numRequestedSamples, GL_RGBA8, m_renderSize, m_renderSize);
226 		GLU_EXPECT_NO_ERROR(gl.getError(), "gen rbo");
227 
228 		gl.genFramebuffers(1, &m_fbo);
229 		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
230 		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_fboRbo);
231 		GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
232 
233 		if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
234 			throw tcu::TestError("fbo not complete");
235 
236 		// logging
237 		gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &queriedSampleCount);
238 		m_testCtx.getLog() << tcu::TestLog::Message << "Asked for " << m_numRequestedSamples << " samples, got " << queriedSampleCount << " samples." << tcu::TestLog::EndMessage;
239 
240 		// sanity
241 		if (queriedSampleCount < m_numRequestedSamples)
242 			throw tcu::TestError("Got less renderbuffer samples samples than asked for");
243 	}
244 
245 	// fbo for resolving the multisample fbo
246 	if (m_renderTarget != TARGET_DEFAULT)
247 	{
248 		gl.genTextures(1, &m_resolveFboTexture);
249 		gl.bindTexture(GL_TEXTURE_2D, m_resolveFboTexture);
250 		gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, m_renderSize, m_renderSize);
251 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
252 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
253 		GLU_EXPECT_NO_ERROR(gl.getError(), "gen tex");
254 
255 		gl.genFramebuffers(1, &m_resolveFbo);
256 		gl.bindFramebuffer(GL_FRAMEBUFFER, m_resolveFbo);
257 		gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_resolveFboTexture, 0);
258 		GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
259 
260 		if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
261 			throw tcu::TestError("resolve fbo not complete");
262 	}
263 
264 	// create verifier shader and set targetSampleCount
265 
266 	{
267 		int realSampleCount = -1;
268 
269 		if (m_renderTarget == TARGET_TEXTURE)
270 		{
271 			if (m_numRequestedSamples == 0)
272 				realSampleCount = 1; // non msaa texture
273 			else
274 				realSampleCount = de::max(1, queriedSampleCount); // msaa texture
275 		}
276 		else if (m_renderTarget == TARGET_RENDERBUFFER)
277 		{
278 			realSampleCount = de::max(1, queriedSampleCount); // msaa rbo
279 		}
280 		else if (m_renderTarget == TARGET_DEFAULT)
281 		{
282 			realSampleCount = de::max(1, m_context.getRenderTarget().getNumSamples());
283 		}
284 		else
285 			DE_ASSERT(DE_FALSE);
286 
287 		// is set and is valid
288 		DE_ASSERT(realSampleCount != -1);
289 		DE_ASSERT(realSampleCount != 0);
290 		m_numTargetSamples = realSampleCount;
291 	}
292 
293 	if (!m_perIterationShader)
294 	{
295 		m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(genVertexSource(m_numTargetSamples)) << glu::FragmentSource(genFragmentSource(m_numTargetSamples)));
296 		m_testCtx.getLog() << tcu::TestLog::Section("RenderShader", "Render shader") << *m_program << tcu::TestLog::EndSection;
297 		if (!m_program->isOk())
298 			throw tcu::TestError("could not build program");
299 
300 	}
301 }
302 
deinit(void)303 void MultisampleRenderCase::deinit (void)
304 {
305 	if (m_buffer)
306 	{
307 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buffer);
308 		m_buffer = 0;
309 	}
310 
311 	if (m_resolveBuffer)
312 	{
313 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_resolveBuffer);
314 		m_resolveBuffer = 0;
315 	}
316 
317 	delete m_program;
318 	m_program = DE_NULL;
319 
320 	if (m_fbo)
321 	{
322 		m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fbo);
323 		m_fbo = 0;
324 	}
325 
326 	if (m_fboTexture)
327 	{
328 		m_context.getRenderContext().getFunctions().deleteTextures(1, &m_fboTexture);
329 		m_fboTexture = 0;
330 	}
331 
332 	delete m_textureSamplerProgram;
333 	m_textureSamplerProgram = DE_NULL;
334 
335 	if (m_fboRbo)
336 	{
337 		m_context.getRenderContext().getFunctions().deleteRenderbuffers(1, &m_fboRbo);
338 		m_fboRbo = 0;
339 	}
340 
341 	if (m_resolveFbo)
342 	{
343 		m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_resolveFbo);
344 		m_resolveFbo = 0;
345 	}
346 
347 	if (m_resolveFboTexture)
348 	{
349 		m_context.getRenderContext().getFunctions().deleteTextures(1, &m_resolveFboTexture);
350 		m_resolveFboTexture = 0;
351 	}
352 
353 	if (m_renderVao)
354 	{
355 		m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_renderVao);
356 		m_renderVao = 0;
357 	}
358 
359 	if (m_resolveVao)
360 	{
361 		m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_resolveVao);
362 		m_resolveVao = 0;
363 	}
364 }
365 
iterate(void)366 MultisampleRenderCase::IterateResult MultisampleRenderCase::iterate (void)
367 {
368 	// default value
369 	if (m_iteration == 0)
370 	{
371 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
372 		preTest();
373 	}
374 
375 	drawOneIteration();
376 
377 	// next iteration
378 	++m_iteration;
379 	if (m_iteration < m_numIterations)
380 		return CONTINUE;
381 	else
382 	{
383 		postTest();
384 		return STOP;
385 	}
386 }
387 
preDraw(void)388 void MultisampleRenderCase::preDraw (void)
389 {
390 }
391 
postDraw(void)392 void MultisampleRenderCase::postDraw (void)
393 {
394 }
395 
preTest(void)396 void MultisampleRenderCase::preTest (void)
397 {
398 }
399 
postTest(void)400 void MultisampleRenderCase::postTest (void)
401 {
402 }
403 
verifyResultImageAndSetResult(const tcu::Surface & resultImage)404 void MultisampleRenderCase::verifyResultImageAndSetResult (const tcu::Surface& resultImage)
405 {
406 	// verify using case-specific verification
407 
408 	try
409 	{
410 		if (!verifyImage(resultImage))
411 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
412 	}
413 	catch (const QualityWarning& ex)
414 	{
415 		m_testCtx.getLog() << tcu::TestLog::Message << "Quality warning, error = " << ex.what() << tcu::TestLog::EndMessage;
416 
417 		// Failures are more important than warnings
418 		if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
419 			m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, ex.what());
420 	}
421 }
422 
verifyResultBuffersAndSetResult(const std::vector<tcu::Surface> & resultBuffers)423 void MultisampleRenderCase::verifyResultBuffersAndSetResult (const std::vector<tcu::Surface>& resultBuffers)
424 {
425 	// verify using case-specific verification
426 
427 	try
428 	{
429 		if (!verifySampleBuffers(resultBuffers))
430 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
431 	}
432 	catch (const QualityWarning& ex)
433 	{
434 		m_testCtx.getLog() << tcu::TestLog::Message << "Quality warning, error = " << ex.what() << tcu::TestLog::EndMessage;
435 
436 		// Failures are more important than warnings
437 		if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
438 			m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, ex.what());
439 	}
440 }
441 
getIterationDescription(int iteration) const442 std::string	MultisampleRenderCase::getIterationDescription (int iteration) const
443 {
444 	DE_UNREF(iteration);
445 	DE_ASSERT(false);
446 	return "";
447 }
448 
drawOneIteration(void)449 void MultisampleRenderCase::drawOneIteration (void)
450 {
451 	const glw::Functions&		gl					= m_context.getRenderContext().getFunctions();
452 	const std::string			sectionDescription	= (m_numIterations > 1) ? ("Iteration " + de::toString(m_iteration+1) + "/" + de::toString(m_numIterations) + ": " + getIterationDescription(m_iteration)) : ("Test");
453 	const tcu::ScopedLogSection	section				(m_testCtx.getLog(), "Iteration" + de::toString(m_iteration), sectionDescription);
454 
455 	// Per iteration shader?
456 	if (m_perIterationShader)
457 	{
458 		delete m_program;
459 		m_program = DE_NULL;
460 
461 		m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
462 			<< glu::VertexSource(genVertexSource(m_numTargetSamples))
463 			<< glu::FragmentSource(genFragmentSource(m_numTargetSamples)));
464 		m_testCtx.getLog() << tcu::TestLog::Section("RenderShader", "Render shader") << *m_program << tcu::TestLog::EndSection;
465 		if (!m_program->isOk())
466 			throw tcu::TestError("could not build program");
467 
468 	}
469 
470 	// render
471 	{
472 		if (m_renderTarget == TARGET_TEXTURE || m_renderTarget == TARGET_RENDERBUFFER)
473 		{
474 			gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
475 			GLU_EXPECT_NO_ERROR(gl.getError(), "bind fbo");
476 
477 			m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << m_renderSceneDescription << " with render shader to fbo." << tcu::TestLog::EndMessage;
478 		}
479 		else
480 			m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << m_renderSceneDescription << " with render shader to default framebuffer." << tcu::TestLog::EndMessage;
481 
482 		gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
483 		gl.clear(GL_COLOR_BUFFER_BIT);
484 		gl.viewport(0, 0, m_renderSize, m_renderSize);
485 		GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
486 
487 		gl.bindVertexArray(m_renderVao);
488 		gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer);
489 
490 		// set attribs
491 		DE_ASSERT(!m_renderAttribs.empty());
492 		for (std::map<std::string, Attrib>::const_iterator it = m_renderAttribs.begin(); it != m_renderAttribs.end(); ++it)
493 		{
494 			const deInt32 location = gl.getAttribLocation(m_program->getProgram(), it->first.c_str());
495 
496 			if (location != -1)
497 			{
498 				gl.vertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, it->second.stride, (deUint8*)DE_NULL + it->second.offset);
499 				gl.enableVertexAttribArray(location);
500 			}
501 		}
502 		GLU_EXPECT_NO_ERROR(gl.getError(), "set attrib");
503 
504 		gl.useProgram(m_program->getProgram());
505 		preDraw();
506 		gl.drawArrays(m_renderMode, 0, m_renderCount);
507 		postDraw();
508 		gl.useProgram(0);
509 		gl.bindVertexArray(0);
510 		GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
511 
512 		if (m_renderTarget == TARGET_TEXTURE || m_renderTarget == TARGET_RENDERBUFFER)
513 			gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
514 	}
515 
516 	// read
517 	{
518 		if (m_renderTarget == TARGET_DEFAULT)
519 		{
520 			tcu::Surface resultImage(m_renderSize, m_renderSize);
521 
522 			m_testCtx.getLog() << tcu::TestLog::Message << "Reading pixels from default framebuffer." << tcu::TestLog::EndMessage;
523 
524 			// default directly
525 			glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
526 			GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
527 
528 			// set test result
529 			verifyResultImageAndSetResult(resultImage);
530 		}
531 		else if (m_renderTarget == TARGET_RENDERBUFFER)
532 		{
533 			tcu::Surface resultImage(m_renderSize, m_renderSize);
534 
535 			// rbo by blitting to non-multisample fbo
536 
537 			m_testCtx.getLog() << tcu::TestLog::Message << "Blitting result from fbo to single sample fbo. (Resolve multisample)" << tcu::TestLog::EndMessage;
538 
539 			gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo);
540 			gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolveFbo);
541 			gl.blitFramebuffer(0, 0, m_renderSize, m_renderSize, 0, 0, m_renderSize, m_renderSize, GL_COLOR_BUFFER_BIT, GL_NEAREST);
542 			GLU_EXPECT_NO_ERROR(gl.getError(), "blit resolve");
543 
544 			m_testCtx.getLog() << tcu::TestLog::Message << "Reading pixels from single sample framebuffer." << tcu::TestLog::EndMessage;
545 
546 			gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_resolveFbo);
547 			glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
548 			GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
549 
550 			gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
551 
552 			// set test result
553 			verifyResultImageAndSetResult(resultImage);
554 		}
555 		else if (m_renderTarget == TARGET_TEXTURE && !m_verifyTextureSampleBuffers)
556 		{
557 			const deInt32	posLocation		= gl.getAttribLocation(m_textureSamplerProgram->getProgram(), "a_position");
558 			const deInt32	samplerLocation	= gl.getUniformLocation(m_textureSamplerProgram->getProgram(), "u_sampler");
559 			const deUint32	textureTarget	= (m_numRequestedSamples == 0) ? (GL_TEXTURE_2D) : (GL_TEXTURE_2D_MULTISAMPLE);
560 			tcu::Surface	resultImage		(m_renderSize, m_renderSize);
561 
562 			if (m_numRequestedSamples)
563 				m_testCtx.getLog() << tcu::TestLog::Message << "Using sampler shader to sample the multisample texture to single sample framebuffer." << tcu::TestLog::EndMessage;
564 			else
565 				m_testCtx.getLog() << tcu::TestLog::Message << "Drawing texture to single sample framebuffer. Using sampler shader." << tcu::TestLog::EndMessage;
566 
567 			if (samplerLocation == -1)
568 				throw tcu::TestError("Location u_sampler was -1.");
569 
570 			// resolve multisample texture by averaging
571 			gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
572 			gl.clear(GL_COLOR_BUFFER_BIT);
573 			gl.viewport(0, 0, m_renderSize, m_renderSize);
574 			GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
575 
576 			gl.bindVertexArray(m_resolveVao);
577 			gl.bindBuffer(GL_ARRAY_BUFFER, m_resolveBuffer);
578 			gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
579 			gl.enableVertexAttribArray(posLocation);
580 			GLU_EXPECT_NO_ERROR(gl.getError(), "set attrib");
581 
582 			gl.activeTexture(GL_TEXTURE0);
583 			gl.bindTexture(textureTarget, m_fboTexture);
584 			GLU_EXPECT_NO_ERROR(gl.getError(), "bind tex");
585 
586 			gl.useProgram(m_textureSamplerProgram->getProgram());
587 			gl.uniform1i(samplerLocation, 0);
588 
589 			gl.bindFramebuffer(GL_FRAMEBUFFER, m_resolveFbo);
590 			gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
591 
592 			gl.useProgram(0);
593 			gl.bindVertexArray(0);
594 			GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
595 
596 			m_testCtx.getLog() << tcu::TestLog::Message << "Reading pixels from single sample framebuffer." << tcu::TestLog::EndMessage;
597 
598 			glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
599 			GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
600 
601 			gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
602 
603 			// set test result
604 			verifyResultImageAndSetResult(resultImage);
605 		}
606 		else if (m_renderTarget == TARGET_TEXTURE && m_verifyTextureSampleBuffers)
607 		{
608 			const deInt32				posLocation		= gl.getAttribLocation(m_textureSamplerProgram->getProgram(), "a_position");
609 			const deInt32				samplerLocation	= gl.getUniformLocation(m_textureSamplerProgram->getProgram(), "u_sampler");
610 			const deInt32				sampleLocation	= gl.getUniformLocation(m_textureSamplerProgram->getProgram(), "u_sampleNdx");
611 			const deUint32				textureTarget	= (m_numRequestedSamples == 0) ? (GL_TEXTURE_2D) : (GL_TEXTURE_2D_MULTISAMPLE);
612 			std::vector<tcu::Surface>	resultBuffers	(m_numTargetSamples);
613 
614 			if (m_numRequestedSamples)
615 				m_testCtx.getLog() << tcu::TestLog::Message << "Reading multisample texture sample buffers." << tcu::TestLog::EndMessage;
616 			else
617 				m_testCtx.getLog() << tcu::TestLog::Message << "Reading texture." << tcu::TestLog::EndMessage;
618 
619 			if (samplerLocation == -1)
620 				throw tcu::TestError("Location u_sampler was -1.");
621 			if (sampleLocation == -1)
622 				throw tcu::TestError("Location u_sampleNdx was -1.");
623 
624 			for (int sampleNdx = 0; sampleNdx < m_numTargetSamples; ++sampleNdx)
625 				resultBuffers[sampleNdx].setSize(m_renderSize, m_renderSize);
626 
627 			// read sample buffers to different surfaces
628 			gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
629 			gl.clear(GL_COLOR_BUFFER_BIT);
630 			gl.viewport(0, 0, m_renderSize, m_renderSize);
631 			GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
632 
633 			gl.bindVertexArray(m_resolveVao);
634 			gl.bindBuffer(GL_ARRAY_BUFFER, m_resolveBuffer);
635 			gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
636 			gl.enableVertexAttribArray(posLocation);
637 			GLU_EXPECT_NO_ERROR(gl.getError(), "set attrib");
638 
639 			gl.activeTexture(GL_TEXTURE0);
640 			gl.bindTexture(textureTarget, m_fboTexture);
641 			GLU_EXPECT_NO_ERROR(gl.getError(), "bind tex");
642 
643 			gl.bindFramebuffer(GL_FRAMEBUFFER, m_resolveFbo);
644 			gl.useProgram(m_textureSamplerProgram->getProgram());
645 			gl.uniform1i(samplerLocation, 0);
646 
647 			m_testCtx.getLog() << tcu::TestLog::Message << "Reading sample buffers" << tcu::TestLog::EndMessage;
648 
649 			for (int sampleNdx = 0; sampleNdx < m_numTargetSamples; ++sampleNdx)
650 			{
651 				gl.uniform1i(sampleLocation, sampleNdx);
652 				gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
653 				GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
654 
655 				glu::readPixels(m_context.getRenderContext(), 0, 0, resultBuffers[sampleNdx].getAccess());
656 				GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
657 			}
658 
659 			gl.useProgram(0);
660 			gl.bindVertexArray(0);
661 			gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
662 
663 			// verify sample buffers
664 			verifyResultBuffersAndSetResult(resultBuffers);
665 		}
666 		else
667 			DE_ASSERT(false);
668 	}
669 }
670 
genVertexSource(int numTargetSamples) const671 std::string	MultisampleRenderCase::genVertexSource (int numTargetSamples) const
672 {
673 	const bool				isES32	= glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
674 	map<string, string>		args;
675 	args["GLSL_VERSION_DECL"]		= isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
676 
677 	DE_UNREF(numTargetSamples);
678 	return std::string(tcu::StringTemplate(s_vertexSource).specialize(args));
679 }
680 
genMSSamplerSource(int numTargetSamples) const681 std::string MultisampleRenderCase::genMSSamplerSource (int numTargetSamples) const
682 {
683 	if (m_verifyTextureSampleBuffers)
684 		return genMSTextureLayerFetchSource(numTargetSamples);
685 	else
686 		return genMSTextureResolverSource(numTargetSamples);
687 }
688 
genMSTextureResolverSource(int numTargetSamples) const689 std::string	MultisampleRenderCase::genMSTextureResolverSource (int numTargetSamples) const
690 {
691 	// default behavior: average
692 
693 	const bool				isES32					= glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
694 	map<string, string>		args;
695 	args["GLSL_VERSION_DECL"]						= isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
696 	const bool				isSingleSampleTarget	= (m_numRequestedSamples == 0);
697 	std::ostringstream		buf;
698 
699 	buf <<	"${GLSL_VERSION_DECL}\n"
700 			"in mediump vec4 v_position;\n"
701 			"layout(location = 0) out mediump vec4 fragColor;\n"
702 			"uniform mediump " << ((isSingleSampleTarget) ? ("sampler2D") : ("sampler2DMS")) << " u_sampler;\n"
703 			"void main (void)\n"
704 			"{\n"
705 			"	mediump vec2 relPosition = (v_position.xy + vec2(1.0, 1.0)) / 2.0;\n"
706 			"	mediump ivec2 fetchPos = ivec2(floor(relPosition * " << m_renderSize << ".0));\n"
707 			"	mediump vec4 colorSum = vec4(0.0, 0.0, 0.0, 0.0);\n"
708 			"\n";
709 
710 	if (isSingleSampleTarget)
711 		buf <<	"	colorSum = texelFetch(u_sampler, fetchPos, 0);\n"
712 				"\n";
713 	else
714 		buf <<	"	for (int sampleNdx = 0; sampleNdx < " << numTargetSamples << "; ++sampleNdx)\n"
715 				"		colorSum += texelFetch(u_sampler, fetchPos, sampleNdx);\n"
716 				"	colorSum /= " << numTargetSamples << ".0;\n"
717 				"\n";
718 
719 	buf <<	"	fragColor = vec4(colorSum.xyz, 1.0);\n"
720 			"}\n";
721 
722 	return tcu::StringTemplate(buf.str()).specialize(args);
723 }
724 
genMSTextureLayerFetchSource(int numTargetSamples) const725 std::string MultisampleRenderCase::genMSTextureLayerFetchSource (int numTargetSamples) const
726 {
727 	DE_UNREF(numTargetSamples);
728 
729 	const bool				isES32					= glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
730 	map<string, string>		args;
731 	args["GLSL_VERSION_DECL"]						= isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
732 	const bool				isSingleSampleTarget	= (m_numRequestedSamples == 0);
733 	std::ostringstream		buf;
734 
735 	buf <<	"${GLSL_VERSION_DECL}\n"
736 			"in mediump vec4 v_position;\n"
737 			"layout(location = 0) out mediump vec4 fragColor;\n"
738 			"uniform mediump " << ((isSingleSampleTarget) ? ("sampler2D") : ("sampler2DMS")) << " u_sampler;\n"
739 			"uniform mediump int u_sampleNdx;\n"
740 			"void main (void)\n"
741 			"{\n"
742 			"	mediump vec2 relPosition = (v_position.xy + vec2(1.0, 1.0)) / 2.0;\n"
743 			"	mediump ivec2 fetchPos = ivec2(floor(relPosition * " << m_renderSize << ".0));\n"
744 			"\n"
745 			"	mediump vec4 color = texelFetch(u_sampler, fetchPos, u_sampleNdx);\n"
746 			"	fragColor = vec4(color.rgb, 1.0);\n"
747 			"}\n";
748 
749 	return tcu::StringTemplate(buf.str()).specialize(args);
750 }
751 
verifySampleBuffers(const std::vector<tcu::Surface> & resultBuffers)752 bool MultisampleRenderCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers)
753 {
754 	DE_UNREF(resultBuffers);
755 	DE_ASSERT(false);
756 	return false;
757 }
758 
setupRenderData(void)759 void MultisampleRenderCase::setupRenderData (void)
760 {
761 	static const tcu::Vec4 fullscreenQuad[] =
762 	{
763 		tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
764 		tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
765 		tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
766 		tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
767 	};
768 
769 	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
770 
771 	m_renderMode = GL_TRIANGLE_STRIP;
772 	m_renderCount = 4;
773 	m_renderSceneDescription = "quad";
774 
775 	m_renderAttribs["a_position"].offset = 0;
776 	m_renderAttribs["a_position"].stride = sizeof(float[4]);
777 
778 	gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer);
779 	gl.bufferData(GL_ARRAY_BUFFER, (int)sizeof(fullscreenQuad), fullscreenQuad, GL_STATIC_DRAW);
780 }
781 
782 } // MultisampleShaderRenderUtil
783 } // Functional
784 } // gles31
785 } // deqp
786