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