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()
129                     << tcu::TestLog::Message << "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()
299             << tcu::TestLog::Message << "glGetProgramPipelineiv with parameter " << pname
300             << " has not returned anything and error has not been generated." << tcu::TestLog::EndMessage;
301 
302         return false;
303     }
304     else
305     {
306         if (expected_value != value)
307         {
308             m_context.getTestContext().getLog()
309                 << tcu::TestLog::Message << "glGetProgramPipelineiv with parameter " << pname << " has returned "
310                 << value << ", however " << expected_value << " 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
440                 << "CreateProgramPipelines has not generated INVALID_VALUE error when callded "
441                    "with negative number of objects to be created."
442                 << "Instead, " << glu::getErrorStr(error) << " error value was generated." << tcu::TestLog::EndMessage;
443         }
444     }
445     catch (...)
446     {
447         is_ok    = false;
448         is_error = true;
449     }
450 
451     /* Cleanup. */
452     if (program_pipeline_dsa)
453     {
454         gl.deleteProgramPipelines(1, &program_pipeline_dsa);
455 
456         program_pipeline_dsa = 0;
457     }
458 
459     /* Result's setup. */
460     if (is_ok)
461     {
462         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
463     }
464     else
465     {
466         if (is_error)
467         {
468             m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
469         }
470         else
471         {
472             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
473         }
474     }
475 
476     return STOP;
477 }
478 
479 /******************************** Functional Test Implementation   ********************************/
480 
481 /** @brief Functional Test constructor.
482  *
483  *  @param [in] context     OpenGL context.
484  */
FunctionalTest(deqp::Context & context)485 FunctionalTest::FunctionalTest(deqp::Context &context)
486     : deqp::TestCase(context, "program_pipelines_functional", "Program Pipeline Objects Functional Test")
487     , m_fbo(0)
488     , m_rbo(0)
489     , m_vao(0)
490     , m_spo_v(0)
491     , m_spo_f(0)
492     , m_ppo(0)
493 {
494     /* Intentionally left blank. */
495 }
496 
497 /** @brief Iterate Functional Test cases.
498  *
499  *  @return Iteration result.
500  */
iterate()501 tcu::TestNode::IterateResult FunctionalTest::iterate()
502 {
503     /* Get context setup. */
504     bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
505     bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
506 
507     if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
508     {
509         m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
510 
511         return STOP;
512     }
513 
514     /* Running tests. */
515     bool is_ok    = true;
516     bool is_error = false;
517 
518     try
519     {
520         prepareFramebuffer();
521         prepareVertexArrayObject();
522         prepareShaderPrograms();
523         preparePipeline();
524         draw();
525 
526         is_ok &= checkFramebufferContent();
527     }
528     catch (...)
529     {
530         is_ok    = false;
531         is_error = true;
532     }
533 
534     /* Clean-up. */
535     clean();
536 
537     /* Result's setup. */
538     if (is_ok)
539     {
540         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
541     }
542     else
543     {
544         if (is_error)
545         {
546             m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
547         }
548         else
549         {
550             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
551         }
552     }
553 
554     return STOP;
555 }
556 
557 /** @brief Function prepares framebuffer with RGBA8 color attachment.
558  *         Viewport is set up. Content of the framebuffer is cleared.
559  *
560  *  @note The function may throw if unexpected error has occured.
561  */
prepareFramebuffer()562 void FunctionalTest::prepareFramebuffer()
563 {
564     /* Shortcut for GL functionality. */
565     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
566 
567     /* Prepare framebuffer. */
568     gl.genFramebuffers(1, &m_fbo);
569     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers call failed.");
570 
571     gl.genRenderbuffers(1, &m_rbo);
572     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers call failed.");
573 
574     gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
575     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer call failed.");
576 
577     gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo);
578     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer call failed.");
579 
580     gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1 /* x size */, 1 /* y size */);
581     GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage call failed.");
582 
583     gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo);
584     GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer call failed.");
585 
586     if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
587     {
588         throw 0;
589     }
590 
591     gl.viewport(0, 0, 1, 1);
592     GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport call failed.");
593 
594     /* Clear framebuffer's content. */
595     gl.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
596     GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor call failed.");
597 
598     gl.clear(GL_COLOR_BUFFER_BIT);
599     GLU_EXPECT_NO_ERROR(gl.getError(), "glClear call failed.");
600 }
601 
602 /** @brief Function generate and bind empty vertex array object.
603  *
604  *  @note The function may throw if unexpected error has occured.
605  */
prepareVertexArrayObject()606 void FunctionalTest::prepareVertexArrayObject()
607 {
608     /* Shortcut for GL functionality */
609     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
610 
611     gl.genVertexArrays(1, &m_vao);
612     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
613 
614     gl.bindVertexArray(m_vao);
615     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
616 }
617 
618 /** @brief Function builds test's GLSL shader program.
619  *         If succeded, the program will be set to be used.
620  *
621  *  @note The function may throw if unexpected error has occured.
622  */
prepareShaderPrograms()623 void FunctionalTest::prepareShaderPrograms()
624 {
625     /* Shortcut for GL functionality. */
626     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
627 
628     /* Log size limit. */
629     static const glw::GLsizei max_log_size = 4096;
630 
631     /* Quick check. */
632     if (m_spo_v || m_spo_f)
633     {
634         throw 0;
635     }
636 
637     /* Create Vertex Shader Program. */
638     m_spo_v = gl.createShaderProgramv(GL_VERTEX_SHADER, 1, &s_vertex_shader);
639     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv call failed.");
640 
641     glw::GLint status = GL_TRUE;
642 
643     gl.validateProgram(m_spo_v);
644     GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgram call failed.");
645 
646     gl.getProgramiv(m_spo_v, GL_VALIDATE_STATUS, &status);
647     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv call failed.");
648 
649     if (GL_FALSE == status)
650     {
651         /* Storage for data. */
652         glw::GLchar log[max_log_size] = {0};
653 
654         /* Storage fetched length. */
655         glw::GLsizei log_size = 0;
656 
657         gl.getProgramInfoLog(m_spo_v, max_log_size, &log_size, log);
658         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog call failed.");
659 
660         m_context.getTestContext().getLog()
661             << tcu::TestLog::Message << "Vertex shader program building failed with log: " << log
662             << tcu::TestLog::EndMessage;
663 
664         throw 0;
665     }
666 
667     m_spo_f = gl.createShaderProgramv(GL_FRAGMENT_SHADER, 1, &s_fragment_shader);
668     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv call failed.");
669 
670     status = GL_TRUE;
671 
672     gl.validateProgram(m_spo_f);
673     GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgram call failed.");
674 
675     gl.getProgramiv(m_spo_f, GL_VALIDATE_STATUS, &status);
676     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv call failed.");
677 
678     if (GL_FALSE == status)
679     {
680         /* Storage for data. */
681         glw::GLchar log[max_log_size] = {0};
682 
683         /* Storage fetched length. */
684         glw::GLsizei log_size = 0;
685 
686         gl.getProgramInfoLog(m_spo_f, max_log_size, &log_size, log);
687         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog call failed.");
688 
689         m_context.getTestContext().getLog()
690             << tcu::TestLog::Message << "Fragment shader program building failed with log: " << log
691             << tcu::TestLog::EndMessage;
692 
693         throw 0;
694     }
695 }
696 
697 /** @brief Function prepares program pipeline object.
698  *
699  *  @note The function may throw if unexpected error has occured.
700  */
preparePipeline()701 void FunctionalTest::preparePipeline()
702 {
703     /* Shortcut for GL functionality. */
704     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
705 
706     /* Quick check. */
707     if (m_ppo)
708     {
709         throw 0;
710     }
711 
712     /* Create, use and set up program pipeline. */
713     gl.createProgramPipelines(1, &m_ppo);
714     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgramPipelines call failed.");
715 
716     gl.bindProgramPipeline(m_ppo);
717     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline call failed.");
718 
719     gl.useProgramStages(m_ppo, GL_VERTEX_SHADER_BIT, m_spo_v);
720     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages call failed.");
721 
722     gl.useProgramStages(m_ppo, GL_FRAGMENT_SHADER_BIT, m_spo_f);
723     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages call failed.");
724 }
725 
726 /** @brief Function draws a quad.
727  *
728  *  @note The function may throw if unexpected error has occured.
729  */
draw()730 void FunctionalTest::draw()
731 {
732     /* Shortcut for GL functionality. */
733     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
734 
735     gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
736     GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays have failed");
737 }
738 
739 /** @brief Check content of the framebuffer and compare it with expected data.
740  *
741  *  @note The function may throw if unexpected error has occured.
742  *
743  *  @return True if succeeded, false otherwise.
744  */
checkFramebufferContent()745 bool FunctionalTest::checkFramebufferContent()
746 {
747     /* Shortcut for GL functionality. */
748     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
749 
750     /* Fetch framebuffer data. */
751     glw::GLubyte pixel[4] = {0};
752 
753     gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
754     GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels have failed");
755 
756     /* Comparison with expected values. */
757     if ((255 != pixel[0]) || (0 != pixel[1]) || (0 != pixel[2]) || (255 != pixel[3]))
758     {
759         m_context.getTestContext().getLog()
760             << tcu::TestLog::Message << "Frameuffer content (" << (unsigned int)pixel[0] << ", "
761             << (unsigned int)pixel[1] << ", " << (unsigned int)pixel[2] << ", " << (unsigned int)pixel[3]
762             << ") is different than expected (255, 0, 0, 255)." << tcu::TestLog::EndMessage;
763 
764         return false;
765     }
766 
767     return true;
768 }
769 
770 /** @brief Release all GL objects.
771  */
clean()772 void FunctionalTest::clean()
773 {
774     /* Shortcut for GL functionality. */
775     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
776 
777     /* Release framebuffer. */
778     if (m_fbo)
779     {
780         gl.deleteFramebuffers(1, &m_fbo);
781 
782         m_fbo = 0;
783     }
784 
785     /* Release renderbuffer. */
786     if (m_rbo)
787     {
788         gl.deleteRenderbuffers(1, &m_rbo);
789 
790         m_rbo = 0;
791     }
792 
793     /* Release vertex array object. */
794     if (m_vao)
795     {
796         gl.deleteVertexArrays(1, &m_vao);
797 
798         m_vao = 0;
799     }
800 
801     /* Release shader programs. */
802     if (m_spo_v)
803     {
804         gl.deleteProgram(m_spo_v);
805 
806         m_spo_v = 0;
807     }
808 
809     if (m_spo_f)
810     {
811         gl.deleteProgram(m_spo_f);
812 
813         m_spo_f = 0;
814     }
815 
816     /* Release program pipelines. */
817     if (m_ppo)
818     {
819         gl.bindProgramPipeline(0);
820 
821         gl.deleteProgramPipelines(1, &m_ppo);
822 
823         m_ppo = 0;
824     }
825 }
826 
827 /* Vertex shader source code. */
828 const glw::GLchar *FunctionalTest::s_vertex_shader = "#version 450\n"
829                                                      "\n"
830                                                      "out gl_PerVertex\n"
831                                                      "{\n"
832                                                      "    vec4  gl_Position;\n"
833                                                      "    float gl_PointSize;\n"
834                                                      "    float gl_ClipDistance[];\n"
835                                                      "};\n"
836                                                      "\n"
837                                                      "void main()\n"
838                                                      "{\n"
839                                                      "    switch(gl_VertexID)\n"
840                                                      "    {\n"
841                                                      "        case 0:\n"
842                                                      "            gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n"
843                                                      "            break;\n"
844                                                      "        case 1:\n"
845                                                      "            gl_Position = vec4( 1.0, 1.0, 0.0, 1.0);\n"
846                                                      "            break;\n"
847                                                      "        case 2:\n"
848                                                      "            gl_Position = vec4(-1.0,-1.0, 0.0, 1.0);\n"
849                                                      "            break;\n"
850                                                      "        case 3:\n"
851                                                      "            gl_Position = vec4( 1.0,-1.0, 0.0, 1.0);\n"
852                                                      "            break;\n"
853                                                      "    }\n"
854                                                      "}\n";
855 
856 /* Fragment shader source program. */
857 const glw::GLchar *FunctionalTest::s_fragment_shader = "#version 450\n"
858                                                        "\n"
859                                                        "out vec4 color;\n"
860                                                        "\n"
861                                                        "void main()\n"
862                                                        "{\n"
863                                                        "    color = vec4(1.0, 0.0, 0.0, 1.0);\n"
864                                                        "}\n";
865 
866 } // namespace ProgramPipelines
867 } // namespace DirectStateAccess
868 } // namespace gl4cts
869