1/*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2015-2016 The Khronos Group Inc.
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
22 */ /*-------------------------------------------------------------------*/
23
24/**
25 */ /*!
26 * \file  gl4cDirectStateAccessProgramPipelinesTests.cpp
27 * \brief Conformance tests for the Direct State Access feature functionality (Program Pipelines part).
28 */ /*-----------------------------------------------------------------------------------------------------------*/
29
30/* Includes. */
31#include "gl4cDirectStateAccessTests.hpp"
32
33#include "deSharedPtr.hpp"
34
35#include "gluContextInfo.hpp"
36#include "gluDefs.hpp"
37#include "gluPixelTransfer.hpp"
38#include "gluStrUtil.hpp"
39
40#include "tcuFuzzyImageCompare.hpp"
41#include "tcuImageCompare.hpp"
42#include "tcuRenderTarget.hpp"
43#include "tcuSurface.hpp"
44#include "tcuTestLog.hpp"
45
46#include "glw.h"
47#include "glwFunctions.hpp"
48
49namespace gl4cts
50{
51namespace DirectStateAccess
52{
53namespace ProgramPipelines
54{
55/******************************** Creation Test Implementation   ********************************/
56
57/** @brief Creation Test constructor.
58 *
59 *  @param [in] context     OpenGL context.
60 */
61CreationTest::CreationTest(deqp::Context& context)
62	: deqp::TestCase(context, "program_pipelines_creation", "Program Pipeline Objects Creation Test")
63{
64	/* Intentionally left blank. */
65}
66
67/** @brief Iterate Creation Test cases.
68 *
69 *  @return Iteration result.
70 */
71tcu::TestNode::IterateResult CreationTest::iterate()
72{
73	/* Shortcut for GL functionality */
74	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
75
76	/* Get context setup. */
77	bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
78	bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
79
80	if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
81	{
82		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
83
84		return STOP;
85	}
86
87	/* Running tests. */
88	bool is_ok	= true;
89	bool is_error = false;
90
91	/* Program pipeline objects */
92	static const glw::GLuint program_pipelines_count = 2;
93
94	glw::GLuint program_pipelines_legacy[program_pipelines_count] = {};
95	glw::GLuint program_pipelines_dsa[program_pipelines_count]	= {};
96
97	try
98	{
99		/* Check legacy state creation. */
100		gl.genProgramPipelines(program_pipelines_count, program_pipelines_legacy);
101		GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines have failed");
102
103		for (glw::GLuint i = 0; i < program_pipelines_count; ++i)
104		{
105			if (gl.isProgramPipeline(program_pipelines_legacy[i]))
106			{
107				is_ok = false;
108
109				/* Log. */
110				m_context.getTestContext().getLog()
111					<< tcu::TestLog::Message
112					<< "GenProgramPipelines has created default objects, but it should create only a names."
113					<< tcu::TestLog::EndMessage;
114			}
115		}
116
117		/* Check direct state creation. */
118		gl.createProgramPipelines(program_pipelines_count, program_pipelines_dsa);
119		GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgramPipelines have failed");
120
121		for (glw::GLuint i = 0; i < program_pipelines_count; ++i)
122		{
123			if (!gl.isProgramPipeline(program_pipelines_dsa[i]))
124			{
125				is_ok = false;
126
127				/* Log. */
128				m_context.getTestContext().getLog() << tcu::TestLog::Message
129													<< "CreateProgramPipelines has not created default objects."
130													<< tcu::TestLog::EndMessage;
131			}
132		}
133	}
134	catch (...)
135	{
136		is_ok	= false;
137		is_error = true;
138	}
139
140	/* Cleanup. */
141	for (glw::GLuint i = 0; i < program_pipelines_count; ++i)
142	{
143		if (program_pipelines_legacy[i])
144		{
145			gl.deleteProgramPipelines(1, &program_pipelines_legacy[i]);
146
147			program_pipelines_legacy[i] = 0;
148		}
149
150		if (program_pipelines_dsa[i])
151		{
152			gl.deleteProgramPipelines(1, &program_pipelines_dsa[i]);
153
154			program_pipelines_dsa[i] = 0;
155		}
156	}
157
158	/* Result's setup. */
159	if (is_ok)
160	{
161		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
162	}
163	else
164	{
165		if (is_error)
166		{
167			m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
168		}
169		else
170		{
171			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
172		}
173	}
174
175	return STOP;
176}
177
178/******************************** Defaults Test Implementation   ********************************/
179
180/** @brief Defaults Test constructor.
181 *
182 *  @param [in] context     OpenGL context.
183 */
184DefaultsTest::DefaultsTest(deqp::Context& context)
185	: deqp::TestCase(context, "program_pipelines_defaults", "Program Pipelines Defaults Test")
186	, m_program_pipeline_dsa(0)
187{
188	/* Intentionally left blank. */
189}
190
191/** @brief Iterate Defaults Test cases.
192 *
193 *  @return Iteration result.
194 */
195tcu::TestNode::IterateResult DefaultsTest::iterate()
196{
197	/* Get context setup. */
198	bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
199	bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
200
201	if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
202	{
203		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
204
205		return STOP;
206	}
207
208	/* Running tests. */
209	bool is_ok	= true;
210	bool is_error = false;
211
212	try
213	{
214		prepare();
215
216		is_ok &= testProgramPipelineParameter(GL_ACTIVE_PROGRAM, 0);
217		is_ok &= testProgramPipelineParameter(GL_VERTEX_SHADER, 0);
218		is_ok &= testProgramPipelineParameter(GL_GEOMETRY_SHADER, 0);
219		is_ok &= testProgramPipelineParameter(GL_FRAGMENT_SHADER, 0);
220		is_ok &= testProgramPipelineParameter(GL_COMPUTE_SHADER, 0);
221		is_ok &= testProgramPipelineParameter(GL_TESS_CONTROL_SHADER, 0);
222		is_ok &= testProgramPipelineParameter(GL_TESS_EVALUATION_SHADER, 0);
223		is_ok &= testProgramPipelineParameter(GL_VALIDATE_STATUS, 0);
224		is_ok &= testProgramPipelineParameter(GL_INFO_LOG_LENGTH, 0);
225
226		is_ok &= testProgramPipelineInfoLog(DE_NULL);
227	}
228	catch (...)
229	{
230		is_ok	= false;
231		is_error = true;
232	}
233
234	/* Clean up. */
235	clean();
236
237	/* Result's setup. */
238	if (is_ok)
239	{
240		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
241	}
242	else
243	{
244		if (is_error)
245		{
246			m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
247		}
248		else
249		{
250			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
251		}
252	}
253
254	return STOP;
255}
256
257/** @brief Create Program Pipeline Objects.
258 *
259 *  @note The function may throw if unexpected error has occured.
260 *
261 *  @return True if test succeeded, false otherwise.
262 */
263void DefaultsTest::prepare()
264{
265	/* Shortcut for GL functionality */
266	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
267
268	/* Program Pipeline object creation */
269	gl.createProgramPipelines(1, &m_program_pipeline_dsa);
270	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgramPipelines have failed");
271}
272
273/** @brief Test if Program Pipeline Parameter has value as expected.
274 *
275 *  @note The function may throw if unexpected error has occured.
276 *
277 *  @param [in] pname           Parameter name enumeration. Must be one of
278 *                              GL_ACTIVE_PROGRAM, GL_VERTEX_SHADER, GL_TESS_CONTROL_SHADER,
279 *                              GL_TESS_EVALUATION_SHADER, GL_GEOMETRY_SHADER,
280 *                              GL_FRAGMENT_SHADER, GL_INFO_LOG_LENGTH.
281 *  @param [in] expected_value  Reference value to be compared.
282 *
283 *  @return True if test succeeded, false otherwise.
284 */
285bool DefaultsTest::testProgramPipelineParameter(glw::GLenum pname, glw::GLint expected_value)
286{
287	/* Shortcut for GL functionality */
288	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
289
290	/* Get data. */
291	glw::GLint value = -1;
292
293	gl.getProgramPipelineiv(m_program_pipeline_dsa, pname, &value);
294	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv have failed");
295
296	if (-1 == value)
297	{
298		m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetProgramPipelineiv with parameter "
299											<< pname << " has not returned anything and error has not been generated."
300											<< tcu::TestLog::EndMessage;
301
302		return false;
303	}
304	else
305	{
306		if (expected_value != value)
307		{
308			m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetProgramPipelineiv with parameter "
309												<< pname << " has returned " << value << ", however " << expected_value
310												<< " was expected." << tcu::TestLog::EndMessage;
311
312			return false;
313		}
314	}
315
316	return true;
317}
318
319/** @brief Test if Program Pipeline Parameter has value as expected.
320 *
321 *  @note The function may throw if unexpected error has occured.
322 *
323 *  @param [in] expected_value  Reference value to be compared.
324 *
325 *  @return True if test succeeded, false otherwise.
326 */
327bool DefaultsTest::testProgramPipelineInfoLog(glw::GLchar* expected_value)
328{
329	/* Shortcut for GL functionality */
330	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
331
332	/* Comparison limit. */
333	static const glw::GLsizei max_log_size = 4096;
334
335	/* Storage for data. */
336	glw::GLchar log[max_log_size] = { 0 };
337
338	/* Storage fetched length. */
339	glw::GLsizei log_size = 0;
340
341	/* Fetch. */
342	gl.getProgramPipelineInfoLog(m_program_pipeline_dsa, max_log_size, &log_size, log);
343	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineInfoLog have failed");
344
345	/* Comparison. */
346	if (DE_NULL == expected_value)
347	{
348		if (0 != log_size)
349		{
350			m_context.getTestContext().getLog()
351				<< tcu::TestLog::Message
352				<< "glGetProgramPipelineInfoLog returned unexpectedly non-empty string: " << log << "."
353				<< tcu::TestLog::EndMessage;
354
355			return false;
356		}
357
358		return true;
359	}
360
361	if (0 != strcmp(log, expected_value))
362	{
363		m_context.getTestContext().getLog()
364			<< tcu::TestLog::Message << "glGetProgramPipelineInfoLog returned string: " << log
365			<< ", but is not the same as expected: " << expected_value << "." << tcu::TestLog::EndMessage;
366
367		return false;
368	}
369
370	return true;
371}
372
373/** @brief Release GL objects.
374 */
375void DefaultsTest::clean()
376{
377	/* Shortcut for GL functionality */
378	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
379
380	if (m_program_pipeline_dsa)
381	{
382		gl.deleteProgramPipelines(1, &m_program_pipeline_dsa);
383
384		m_program_pipeline_dsa = 0;
385	}
386}
387
388/******************************** Errors Test Implementation   ********************************/
389
390/** @brief Errors Test constructor.
391 *
392 *  @param [in] context     OpenGL context.
393 */
394ErrorsTest::ErrorsTest(deqp::Context& context)
395	: deqp::TestCase(context, "program_pipelines_errors", "Program Pipeline Objects Errors Test")
396{
397	/* Intentionally left blank. */
398}
399
400/** @brief Iterate Errors Test cases.
401 *
402 *  @return Iteration result.
403 */
404tcu::TestNode::IterateResult ErrorsTest::iterate()
405{
406	/* Shortcut for GL functionality */
407	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
408
409	/* Get context setup. */
410	bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
411	bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
412
413	if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
414	{
415		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
416
417		return STOP;
418	}
419
420	/* Running tests. */
421	bool is_ok	= true;
422	bool is_error = false;
423
424	glw::GLuint program_pipeline_dsa = 0;
425
426	try
427	{
428		/* Check direct state creation. */
429		gl.createProgramPipelines(-1, &program_pipeline_dsa);
430
431		glw::GLenum error = GL_NO_ERROR;
432
433		if (GL_INVALID_VALUE != (error = gl.getError()))
434		{
435			is_ok = false;
436
437			/* Log. */
438			m_context.getTestContext().getLog()
439				<< tcu::TestLog::Message << "CreateProgramPipelines has not generated INVALID_VALUE error when callded "
440											"with negative number of objects to be created."
441				<< "Instead, " << glu::getErrorStr(error) << " error value was generated." << tcu::TestLog::EndMessage;
442		}
443	}
444	catch (...)
445	{
446		is_ok	= false;
447		is_error = true;
448	}
449
450	/* Cleanup. */
451	if (program_pipeline_dsa)
452	{
453		gl.deleteProgramPipelines(1, &program_pipeline_dsa);
454
455		program_pipeline_dsa = 0;
456	}
457
458	/* Result's setup. */
459	if (is_ok)
460	{
461		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
462	}
463	else
464	{
465		if (is_error)
466		{
467			m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
468		}
469		else
470		{
471			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
472		}
473	}
474
475	return STOP;
476}
477
478/******************************** Functional Test Implementation   ********************************/
479
480/** @brief Functional Test constructor.
481 *
482 *  @param [in] context     OpenGL context.
483 */
484FunctionalTest::FunctionalTest(deqp::Context& context)
485	: deqp::TestCase(context, "program_pipelines_functional", "Program Pipeline Objects Functional Test")
486	, m_fbo(0)
487	, m_rbo(0)
488	, m_vao(0)
489	, m_spo_v(0)
490	, m_spo_f(0)
491	, m_ppo(0)
492{
493	/* Intentionally left blank. */
494}
495
496/** @brief Iterate Functional Test cases.
497 *
498 *  @return Iteration result.
499 */
500tcu::TestNode::IterateResult FunctionalTest::iterate()
501{
502	/* Get context setup. */
503	bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
504	bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
505
506	if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
507	{
508		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
509
510		return STOP;
511	}
512
513	/* Running tests. */
514	bool is_ok	= true;
515	bool is_error = false;
516
517	try
518	{
519		prepareFramebuffer();
520		prepareVertexArrayObject();
521		prepareShaderPrograms();
522		preparePipeline();
523		draw();
524
525		is_ok &= checkFramebufferContent();
526	}
527	catch (...)
528	{
529		is_ok	= false;
530		is_error = true;
531	}
532
533	/* Clean-up. */
534	clean();
535
536	/* Result's setup. */
537	if (is_ok)
538	{
539		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
540	}
541	else
542	{
543		if (is_error)
544		{
545			m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
546		}
547		else
548		{
549			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
550		}
551	}
552
553	return STOP;
554}
555
556/** @brief Function prepares framebuffer with RGBA8 color attachment.
557 *         Viewport is set up. Content of the framebuffer is cleared.
558 *
559 *  @note The function may throw if unexpected error has occured.
560 */
561void FunctionalTest::prepareFramebuffer()
562{
563	/* Shortcut for GL functionality. */
564	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
565
566	/* Prepare framebuffer. */
567	gl.genFramebuffers(1, &m_fbo);
568	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers call failed.");
569
570	gl.genRenderbuffers(1, &m_rbo);
571	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers call failed.");
572
573	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
574	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer call failed.");
575
576	gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo);
577	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer call failed.");
578
579	gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1 /* x size */, 1 /* y size */);
580	GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage call failed.");
581
582	gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo);
583	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer call failed.");
584
585	if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
586	{
587		throw 0;
588	}
589
590	gl.viewport(0, 0, 1, 1);
591	GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport call failed.");
592
593	/* Clear framebuffer's content. */
594	gl.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
595	GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor call failed.");
596
597	gl.clear(GL_COLOR_BUFFER_BIT);
598	GLU_EXPECT_NO_ERROR(gl.getError(), "glClear call failed.");
599}
600
601/** @brief Function generate and bind empty vertex array object.
602 *
603 *  @note The function may throw if unexpected error has occured.
604 */
605void FunctionalTest::prepareVertexArrayObject()
606{
607	/* Shortcut for GL functionality */
608	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
609
610	gl.genVertexArrays(1, &m_vao);
611	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
612
613	gl.bindVertexArray(m_vao);
614	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
615}
616
617/** @brief Function builds test's GLSL shader program.
618 *         If succeded, the program will be set to be used.
619 *
620 *  @note The function may throw if unexpected error has occured.
621 */
622void FunctionalTest::prepareShaderPrograms()
623{
624	/* Shortcut for GL functionality. */
625	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
626
627	/* Log size limit. */
628	static const glw::GLsizei max_log_size = 4096;
629
630	/* Quick check. */
631	if (m_spo_v || m_spo_f)
632	{
633		throw 0;
634	}
635
636	/* Create Vertex Shader Program. */
637	m_spo_v = gl.createShaderProgramv(GL_VERTEX_SHADER, 1, &s_vertex_shader);
638	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv call failed.");
639
640	glw::GLint status = GL_TRUE;
641
642	gl.validateProgram(m_spo_v);
643	GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgram call failed.");
644
645	gl.getProgramiv(m_spo_v, GL_VALIDATE_STATUS, &status);
646	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv call failed.");
647
648	if (GL_FALSE == status)
649	{
650		/* Storage for data. */
651		glw::GLchar log[max_log_size] = { 0 };
652
653		/* Storage fetched length. */
654		glw::GLsizei log_size = 0;
655
656		gl.getProgramInfoLog(m_spo_v, max_log_size, &log_size, log);
657		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog call failed.");
658
659		m_context.getTestContext().getLog() << tcu::TestLog::Message
660											<< "Vertex shader program building failed with log: " << log
661											<< tcu::TestLog::EndMessage;
662
663		throw 0;
664	}
665
666	m_spo_f = gl.createShaderProgramv(GL_FRAGMENT_SHADER, 1, &s_fragment_shader);
667	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv call failed.");
668
669	status = GL_TRUE;
670
671	gl.validateProgram(m_spo_f);
672	GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgram call failed.");
673
674	gl.getProgramiv(m_spo_f, GL_VALIDATE_STATUS, &status);
675	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv call failed.");
676
677	if (GL_FALSE == status)
678	{
679		/* Storage for data. */
680		glw::GLchar log[max_log_size] = { 0 };
681
682		/* Storage fetched length. */
683		glw::GLsizei log_size = 0;
684
685		gl.getProgramInfoLog(m_spo_f, max_log_size, &log_size, log);
686		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog call failed.");
687
688		m_context.getTestContext().getLog() << tcu::TestLog::Message
689											<< "Fragment shader program building failed with log: " << log
690											<< tcu::TestLog::EndMessage;
691
692		throw 0;
693	}
694}
695
696/** @brief Function prepares program pipeline object.
697 *
698 *  @note The function may throw if unexpected error has occured.
699 */
700void FunctionalTest::preparePipeline()
701{
702	/* Shortcut for GL functionality. */
703	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
704
705	/* Quick check. */
706	if (m_ppo)
707	{
708		throw 0;
709	}
710
711	/* Create, use and set up program pipeline. */
712	gl.createProgramPipelines(1, &m_ppo);
713	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgramPipelines call failed.");
714
715	gl.bindProgramPipeline(m_ppo);
716	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline call failed.");
717
718	gl.useProgramStages(m_ppo, GL_VERTEX_SHADER_BIT, m_spo_v);
719	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages call failed.");
720
721	gl.useProgramStages(m_ppo, GL_FRAGMENT_SHADER_BIT, m_spo_f);
722	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages call failed.");
723}
724
725/** @brief Function draws a quad.
726 *
727 *  @note The function may throw if unexpected error has occured.
728 */
729void FunctionalTest::draw()
730{
731	/* Shortcut for GL functionality. */
732	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
733
734	gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
735	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays have failed");
736}
737
738/** @brief Check content of the framebuffer and compare it with expected data.
739 *
740 *  @note The function may throw if unexpected error has occured.
741 *
742 *  @return True if succeeded, false otherwise.
743 */
744bool FunctionalTest::checkFramebufferContent()
745{
746	/* Shortcut for GL functionality. */
747	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
748
749	/* Fetch framebuffer data. */
750	glw::GLubyte pixel[4] = { 0 };
751
752	gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
753	GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels have failed");
754
755	/* Comparison with expected values. */
756	if ((255 != pixel[0]) || (0 != pixel[1]) || (0 != pixel[2]) || (255 != pixel[3]))
757	{
758		m_context.getTestContext().getLog()
759			<< tcu::TestLog::Message << "Frameuffer content (" << (unsigned int)pixel[0] << ", "
760			<< (unsigned int)pixel[1] << ", " << (unsigned int)pixel[2] << ", " << (unsigned int)pixel[3]
761			<< ") is different than expected (255, 0, 0, 255)." << tcu::TestLog::EndMessage;
762
763		return false;
764	}
765
766	return true;
767}
768
769/** @brief Release all GL objects.
770 */
771void FunctionalTest::clean()
772{
773	/* Shortcut for GL functionality. */
774	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
775
776	/* Release framebuffer. */
777	if (m_fbo)
778	{
779		gl.deleteFramebuffers(1, &m_fbo);
780
781		m_fbo = 0;
782	}
783
784	/* Release renderbuffer. */
785	if (m_rbo)
786	{
787		gl.deleteRenderbuffers(1, &m_rbo);
788
789		m_rbo = 0;
790	}
791
792	/* Release vertex array object. */
793	if (m_vao)
794	{
795		gl.deleteVertexArrays(1, &m_vao);
796
797		m_vao = 0;
798	}
799
800	/* Release shader programs. */
801	if (m_spo_v)
802	{
803		gl.deleteProgram(m_spo_v);
804
805		m_spo_v = 0;
806	}
807
808	if (m_spo_f)
809	{
810		gl.deleteProgram(m_spo_f);
811
812		m_spo_f = 0;
813	}
814
815	/* Release program pipelines. */
816	if (m_ppo)
817	{
818		gl.bindProgramPipeline(0);
819
820		gl.deleteProgramPipelines(1, &m_ppo);
821
822		m_ppo = 0;
823	}
824}
825
826/* Vertex shader source code. */
827const glw::GLchar* FunctionalTest::s_vertex_shader = "#version 450\n"
828													 "\n"
829													 "out gl_PerVertex\n"
830													 "{\n"
831													 "    vec4  gl_Position;\n"
832													 "    float gl_PointSize;\n"
833													 "    float gl_ClipDistance[];\n"
834													 "};\n"
835													 "\n"
836													 "void main()\n"
837													 "{\n"
838													 "    switch(gl_VertexID)\n"
839													 "    {\n"
840													 "        case 0:\n"
841													 "            gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n"
842													 "            break;\n"
843													 "        case 1:\n"
844													 "            gl_Position = vec4( 1.0, 1.0, 0.0, 1.0);\n"
845													 "            break;\n"
846													 "        case 2:\n"
847													 "            gl_Position = vec4(-1.0,-1.0, 0.0, 1.0);\n"
848													 "            break;\n"
849													 "        case 3:\n"
850													 "            gl_Position = vec4( 1.0,-1.0, 0.0, 1.0);\n"
851													 "            break;\n"
852													 "    }\n"
853													 "}\n";
854
855/* Fragment shader source program. */
856const glw::GLchar* FunctionalTest::s_fragment_shader = "#version 450\n"
857													   "\n"
858													   "out vec4 color;\n"
859													   "\n"
860													   "void main()\n"
861													   "{\n"
862													   "    color = vec4(1.0, 0.0, 0.0, 1.0);\n"
863													   "}\n";
864
865} /* ProgramPipelines namespace. */
866} /* DirectStateAccess namespace. */
867} /* gl4cts namespace. */
868