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
35namespace deqp
36{
37namespace gles31
38{
39namespace Functional
40{
41namespace MultisampleShaderRenderUtil
42{
43namespace
44{
45
46static 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
57QualityWarning::QualityWarning (const std::string& message)
58	: tcu::Exception(message)
59{
60}
61
62MultisampleRenderCase::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
89MultisampleRenderCase::~MultisampleRenderCase (void)
90{
91	MultisampleRenderCase::deinit();
92}
93
94void 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
295void 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
358MultisampleRenderCase::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
380void MultisampleRenderCase::preDraw (void)
381{
382}
383
384void MultisampleRenderCase::postDraw (void)
385{
386}
387
388void MultisampleRenderCase::preTest (void)
389{
390}
391
392void MultisampleRenderCase::postTest (void)
393{
394}
395
396void 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
415void 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
434std::string	MultisampleRenderCase::getIterationDescription (int iteration) const
435{
436	DE_UNREF(iteration);
437	DE_ASSERT(false);
438	return "";
439}
440
441void 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
661std::string	MultisampleRenderCase::genVertexSource (int numTargetSamples) const
662{
663	DE_UNREF(numTargetSamples);
664	return std::string(s_vertexSource);
665}
666
667std::string MultisampleRenderCase::genMSSamplerSource (int numTargetSamples) const
668{
669	if (m_verifyTextureSampleBuffers)
670		return genMSTextureLayerFetchSource(numTargetSamples);
671	else
672		return genMSTextureResolverSource(numTargetSamples);
673}
674
675std::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
708std::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
732bool MultisampleRenderCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers)
733{
734	DE_UNREF(resultBuffers);
735	DE_ASSERT(false);
736	return false;
737}
738
739void 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