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