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