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 
49 namespace gl4cts
50 {
51 namespace DirectStateAccess
52 {
53 namespace ProgramPipelines
54 {
55 /******************************** Creation Test Implementation   ********************************/
56 
57 /** @brief Creation Test constructor.
58  *
59  *  @param [in] context     OpenGL context.
60  */
CreationTest(deqp::Context & context)61 CreationTest::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  */
iterate()71 tcu::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  */
DefaultsTest(deqp::Context & context)184 DefaultsTest::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  */
iterate()195 tcu::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  */
prepare()263 void 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  */
testProgramPipelineParameter(glw::GLenum pname,glw::GLint expected_value)285 bool 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  */
testProgramPipelineInfoLog(glw::GLchar * expected_value)327 bool 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  */
clean()375 void 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  */
ErrorsTest(deqp::Context & context)394 ErrorsTest::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  */
iterate()404 tcu::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  */
FunctionalTest(deqp::Context & context)484 FunctionalTest::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  */
iterate()500 tcu::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  */
prepareFramebuffer()561 void 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  */
prepareVertexArrayObject()605 void 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  */
prepareShaderPrograms()622 void 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 	/* Sanity 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  */
preparePipeline()700 void FunctionalTest::preparePipeline()
701 {
702 	/* Shortcut for GL functionality. */
703 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
704 
705 	/* Sanity 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  */
draw()729 void 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  */
checkFramebufferContent()744 bool 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  */
clean()771 void 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. */
827 const 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. */
856 const 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