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
37namespace deqp
38{
39namespace gles31
40{
41namespace Functional
42{
43namespace MultisampleShaderRenderUtil
44{
45using std::map;
46using std::string;
47namespace
48{
49
50static 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
61QualityWarning::QualityWarning (const std::string& message)
62	: tcu::Exception(message)
63{
64}
65
66MultisampleRenderCase::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
93MultisampleRenderCase::~MultisampleRenderCase (void)
94{
95	MultisampleRenderCase::deinit();
96}
97
98void 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
301void 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
364MultisampleRenderCase::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
386void MultisampleRenderCase::preDraw (void)
387{
388}
389
390void MultisampleRenderCase::postDraw (void)
391{
392}
393
394void MultisampleRenderCase::preTest (void)
395{
396}
397
398void MultisampleRenderCase::postTest (void)
399{
400}
401
402void 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
421void 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
440std::string	MultisampleRenderCase::getIterationDescription (int iteration) const
441{
442	DE_UNREF(iteration);
443	DE_ASSERT(false);
444	return "";
445}
446
447void 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
669std::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
683std::string MultisampleRenderCase::genMSSamplerSource (int numTargetSamples) const
684{
685	if (m_verifyTextureSampleBuffers)
686		return genMSTextureLayerFetchSource(numTargetSamples);
687	else
688		return genMSTextureResolverSource(numTargetSamples);
689}
690
691std::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
728std::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
756bool MultisampleRenderCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers)
757{
758	DE_UNREF(resultBuffers);
759	DE_ASSERT(false);
760	return false;
761}
762
763void 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
786glw::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