Home | History | Annotate | Download | only in functional
      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 
     60 QualityWarning::QualityWarning (const std::string& message)
     61 	: tcu::Exception(message)
     62 {
     63 }
     64 
     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 
     92 MultisampleRenderCase::~MultisampleRenderCase (void)
     93 {
     94 	MultisampleRenderCase::deinit();
     95 }
     96 
     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 
    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 
    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 
    388 void MultisampleRenderCase::preDraw (void)
    389 {
    390 }
    391 
    392 void MultisampleRenderCase::postDraw (void)
    393 {
    394 }
    395 
    396 void MultisampleRenderCase::preTest (void)
    397 {
    398 }
    399 
    400 void MultisampleRenderCase::postTest (void)
    401 {
    402 }
    403 
    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 
    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 
    442 std::string	MultisampleRenderCase::getIterationDescription (int iteration) const
    443 {
    444 	DE_UNREF(iteration);
    445 	DE_ASSERT(false);
    446 	return "";
    447 }
    448 
    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 
    671 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 
    681 std::string MultisampleRenderCase::genMSSamplerSource (int numTargetSamples) const
    682 {
    683 	if (m_verifyTextureSampleBuffers)
    684 		return genMSTextureLayerFetchSource(numTargetSamples);
    685 	else
    686 		return genMSTextureResolverSource(numTargetSamples);
    687 }
    688 
    689 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 
    725 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 
    752 bool MultisampleRenderCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers)
    753 {
    754 	DE_UNREF(resultBuffers);
    755 	DE_ASSERT(false);
    756 	return false;
    757 }
    758 
    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