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 /* Includes. */
25 #include "gl4cContextFlushControlTests.hpp"
26 #include "deClock.h"
27 #include "gluContextInfo.hpp"
28 #include "gluDefs.hpp"
29 #include "gluPlatform.hpp"
30 #include "gluRenderContext.hpp"
31 #include "gluStrUtil.hpp"
32 #include "tcuTestLog.hpp"
33
34 #ifndef GL_CONTEXT_RELEASE_BEHAVIOR
35 #define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB
36 #endif
37
38 #ifndef GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH
39 #define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC
40 #endif
41
42 #define CONTEXT_FLUSH_CONTROL_FUNCTIONAL_TEST_DRAW_COUNT 1024
43
44 /******************************** Test Group Implementation ********************************/
45
46 /** @brief Context Flush Control tests group constructor.
47 *
48 * @param [in] context OpenGL context.
49 */
Tests(deqp::Context & context)50 gl4cts::ContextFlushControl::Tests::Tests(deqp::Context &context)
51 : TestCaseGroup(context, "context_flush_control", "Context Flush Control Test Suite")
52 {
53 /* Intentionally left blank */
54 }
55
56 /** @brief Context Flush Control tests initializer. */
init()57 void gl4cts::ContextFlushControl::Tests::init()
58 {
59 addChild(new gl4cts::ContextFlushControl::CoverageTest(m_context));
60 addChild(new gl4cts::ContextFlushControl::FunctionalTest(m_context));
61 }
62
63 /******************************** Coverage Tests Implementation ********************************/
64
65 /** @brief API coverage tests constructor.
66 *
67 * @param [in] context OpenGL context.
68 */
CoverageTest(deqp::Context & context)69 gl4cts::ContextFlushControl::CoverageTest::CoverageTest(deqp::Context &context)
70 : deqp::TestCase(context, "coverage", "Context Flush Control API Coverage Test")
71 {
72 /* Intentionally left blank. */
73 }
74
75 /** @brief Iterate API coverage tests.
76 *
77 * @return Iteration result.
78 */
iterate()79 tcu::TestNode::IterateResult gl4cts::ContextFlushControl::CoverageTest::iterate()
80 {
81 /* OpenGL support query. */
82 bool is_at_least_gl_44 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 4)));
83 bool is_khr_context_flush_control = m_context.getContextInfo().isExtensionSupported("GL_KHR_context_flush_control");
84
85 /* Running tests. */
86 bool is_ok = true;
87
88 /* This test should only be executed if we're running a GL4.4 context or related extension is available */
89 if (is_at_least_gl_44 || is_khr_context_flush_control)
90 {
91 /* Test deafult context which shall use implicit flush when swapped. */
92 is_ok = is_ok && testQuery(m_context.getRenderContext(), GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH);
93
94 /* Create context which shall swap without flush. */
95 glu::RenderContext *no_flush_context = createNoFlushContext();
96
97 /* Proceed only if such context has been created. */
98 if (DE_NULL != no_flush_context)
99 {
100 /* Test no-flush context. */
101 no_flush_context->makeCurrent();
102
103 is_ok = is_ok && testQuery(*no_flush_context, GL_NONE);
104
105 /* Release no-flush context. */
106 m_context.getRenderContext().makeCurrent();
107
108 delete no_flush_context;
109 }
110 }
111
112 /* Result's setup. */
113 if (is_ok)
114 {
115 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
116 }
117 else
118 {
119 m_context.getTestContext().getLog()
120 << tcu::TestLog::Message << "The Context Flush Control Coverage test have failed."
121 << tcu::TestLog::EndMessage;
122
123 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
124 }
125
126 return STOP;
127 }
128
129 /** @brief Test getter coverage for the given GL context.
130 *
131 * This function tests following GL query functions:
132 * glGetIntegerv,
133 * glGetFloatv,
134 * glGetBooleanv,
135 * glGetDoublev,
136 * glGetInteger64v.
137 * Expected value is clamped to <0, 1> range flor glGetBooleanv.
138 * For reference see KHR_context_flush_control extension.
139 *
140 * @param [in] context Render context to be used with the test.
141 * @param [in] expected_value Expected value to be returned by glGet*v function.
142 *
143 * @return True if all tested functions returned expected value, false otherwise.
144 */
testQuery(glu::RenderContext & context,glw::GLenum expected_value)145 bool gl4cts::ContextFlushControl::CoverageTest::testQuery(glu::RenderContext &context, glw::GLenum expected_value)
146 {
147 /* Shortcut for GL functionality. */
148 const glw::Functions &gl = context.getFunctions();
149
150 /* Variables for query. */
151 glw::GLint value_i = -1;
152 glw::GLint64 value_i64 = -1;
153 glw::GLfloat value_f = -1;
154 glw::GLdouble value_d = -1;
155 glw::GLboolean value_b = -1;
156
157 glw::GLboolean expected_bool_value = (glw::GLboolean)de::min((glw::GLint)expected_value, (glw::GLint)1);
158
159 /* Test. */
160 try
161 {
162 /* Fetch data. */
163 gl.getIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &value_i);
164 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
165
166 gl.getInteger64v(GL_CONTEXT_RELEASE_BEHAVIOR, &value_i64);
167 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInteger64v call failed.");
168
169 gl.getFloatv(GL_CONTEXT_RELEASE_BEHAVIOR, &value_f);
170 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv call failed.");
171
172 gl.getDoublev(GL_CONTEXT_RELEASE_BEHAVIOR, &value_d);
173 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetDoublev call failed.");
174
175 gl.getBooleanv(GL_CONTEXT_RELEASE_BEHAVIOR, &value_b);
176 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBooleanv call failed.");
177
178 /* Check result. */
179 if ((expected_value == value_i) && (expected_value == value_i64) && (expected_value == value_f) &&
180 (expected_value == value_d) && (expected_bool_value == value_b))
181 {
182 return true;
183 }
184 }
185 catch (...)
186 {
187 return false;
188 }
189
190 return false;
191 }
192
193 /** @brief Create render context with CONTEXT_RELEASE_BEHAVIOR set as NONE.
194 *
195 * @return Render context pointer if creation succeeded, DE_NULL otherwise.
196 */
createNoFlushContext()197 glu::RenderContext *gl4cts::ContextFlushControl::CoverageTest::createNoFlushContext()
198 {
199 /* Get current platform.*/
200 glu::Platform &platform = dynamic_cast<glu::Platform &>(m_context.getTestContext().getPlatform());
201
202 /* Context to be returned (NULL if failed). */
203 glu::RenderContext *context = DE_NULL;
204
205 /* Get context related attributes needed to create no-flush context. */
206 const int *attributes = platform.getContextFlushControlContextAttributes();
207
208 /* Proceed only if it is possible to make no-flush context. */
209 if (DE_NULL != attributes)
210 {
211 glu::ContextType renderContextType = m_context.getRenderContext().getType();
212
213 /* Create no-flush context. */
214 context = platform.createRenderContext(renderContextType, m_context.getTestContext().getCommandLine(),
215 0 /* shared_context */, attributes);
216 }
217
218 return context;
219 }
220
221 /******************************** Functional Test Implementation ********************************/
222
223 /** @brief Functional test constructor.
224 *
225 * @param [in] context OpenGL context.
226 */
FunctionalTest(deqp::Context & context)227 gl4cts::ContextFlushControl::FunctionalTest::FunctionalTest(deqp::Context &context)
228 : deqp::TestCase(context, "functional", "Context Flush Control Functional Test")
229 {
230 /* Intentionally left blank. */
231 }
232
233 /** @brief Iterate Functional test cases.
234 *
235 * @return Iteration result.
236 */
iterate()237 tcu::TestNode::IterateResult gl4cts::ContextFlushControl::FunctionalTest::iterate()
238 {
239 /* Shortcut for GL functionality. */
240 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
241
242 /* Get current platform.*/
243 glu::Platform &platform = dynamic_cast<glu::Platform &>(m_context.getTestContext().getPlatform());
244
245 /* OpenGL support query. */
246 bool is_at_least_gl_44 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 4)));
247 bool is_khr_context_flush_control = m_context.getContextInfo().isExtensionSupported("GL_KHR_context_flush_control");
248
249 /* Running tests. */
250 bool is_ok = true;
251 bool is_error = false;
252
253 /* This test should only be executed if we're running a GL4.4 context or related extension is available */
254 try
255 {
256 if ((is_at_least_gl_44 || is_khr_context_flush_control) &&
257 (DE_NULL != platform.getContextFlushControlContextAttributes()))
258 {
259 glw::GLfloat test_time_no_flush = testTime(false);
260 glw::GLfloat test_time_flush = testTime(true);
261
262 is_ok = (test_time_no_flush < test_time_flush);
263 }
264 else
265 {
266 is_error = true;
267 }
268 }
269 catch (...)
270 {
271 is_ok = false;
272 is_error = true;
273 }
274
275 /* Result's setup. */
276 if (is_ok)
277 {
278 if (is_error)
279 {
280 m_context.getTestContext().getLog()
281 << tcu::TestLog::Message << "The context does not support No-Flush behavior."
282 << tcu::TestLog::EndMessage;
283
284 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported.");
285 }
286 else
287 {
288 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
289 }
290 }
291 else
292 {
293 if (is_error)
294 {
295 m_context.getTestContext().getLog()
296 << tcu::TestLog::Message << "Internal error has occured during Context Flush Control Functional test."
297 << tcu::TestLog::EndMessage;
298
299 m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Test error.");
300 }
301 else
302 {
303 m_context.getTestContext().getLog()
304 << tcu::TestLog::Message
305 << "The running time of no-flush context switches has been slower than flush "
306 "behavior context switching case. "
307 << "This is not expected from quality implementation." << tcu::TestLog::EndMessage;
308
309 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Quality warning.");
310 }
311 }
312
313 return STOP;
314 }
315
316 /** @brief This function measures time of loop consisting of draw and switch context,
317 * which shall or shall not flush on switch.
318 *
319 * The test is based on KHR_context_flush_control extension overview, that the main reason
320 * for no-flush context is to increase the performance of the implementation.
321 *
322 * @param [in] shall_flush_on_release Flag indicating that contexts shall flush when switched.
323 *
324 * @return Run-time of the test loop.
325 */
testTime(bool shall_flush_on_release)326 glw::GLfloat gl4cts::ContextFlushControl::FunctionalTest::testTime(bool shall_flush_on_release)
327 {
328 /* Create two contexts to be switched during test. */
329 DrawSetup draw_context_setup[2] = {DrawSetup(m_context, shall_flush_on_release),
330 DrawSetup(m_context, shall_flush_on_release)};
331
332 /* Check starting time. */
333 uint64_t start_time = deGetMicroseconds();
334
335 /* Loop over draw-switch context. */
336 for (glw::GLuint i = 0; i < 1024; ++i)
337 {
338 draw_context_setup[i % 2].makeCurrent();
339 draw_context_setup[i % 2].draw();
340 }
341
342 /* Check end time. */
343 uint64_t end_time = deGetMicroseconds();
344
345 /* Return resulting run-time. */
346 return (glw::GLfloat)(end_time - start_time);
347 }
348
349 /** @brief Make context current.
350 */
makeCurrent()351 void gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::makeCurrent()
352 {
353 /* Switch context to this. */
354 m_context->makeCurrent();
355 }
356
357 /** @brief Use program and draw full screen quad.
358 */
draw()359 void gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::draw()
360 {
361 /* Shortcut for GL functionality. */
362 const glw::Functions &gl = m_context->getFunctions();
363
364 /* Use GLSL program. */
365 gl.useProgram(m_po);
366 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
367
368 /* Clear. */
369 gl.clear(GL_COLOR_BUFFER_BIT);
370 GLU_EXPECT_NO_ERROR(gl.getError(), "glClear call failed.");
371
372 /* Draw. */
373 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4 /* quad */);
374 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays call failed.");
375 }
376
377 /** @brief Draw Setup object constructor.
378 *
379 * The constructor will throw on error.
380 *
381 * @param [in] test_context Test context for platform, logging and switching to default context on destruction.
382 * @param [in] shall_flush_on_release Flag indicating that contexts shall flush when switched.
383 */
DrawSetup(deqp::Context & test_context,bool shall_flush_on_release)384 gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::DrawSetup(deqp::Context &test_context,
385 bool shall_flush_on_release)
386 : m_test_context(test_context)
387 , m_fbo(0)
388 , m_rbo(0)
389 , m_vao(0)
390 , m_po(0)
391 {
392 createContext(shall_flush_on_release);
393
394 if (DE_NULL == m_context)
395 {
396 throw 0;
397 }
398
399 createGeometry();
400
401 if (0 == m_vao)
402 {
403 throw 0;
404 }
405
406 createView();
407
408 if ((0 == m_fbo) || (0 == m_rbo))
409 {
410 throw 0;
411 }
412
413 createProgram();
414
415 if (0 == m_po)
416 {
417 throw 0;
418 }
419 }
420
421 /** @brief Draw Setup object destructor.
422 */
~DrawSetup()423 gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::~DrawSetup()
424 {
425 if (m_context)
426 {
427 /* Make sure context is current. */
428 makeCurrent();
429
430 /* Shortcut for GL functionality. */
431 const glw::Functions &gl = m_context->getFunctions();
432
433 /* Cleanup. */
434 if (m_vao)
435 {
436 gl.deleteVertexArrays(1, &m_vao);
437
438 m_vao = 0;
439 }
440
441 if (m_fbo)
442 {
443 gl.deleteFramebuffers(1, &m_fbo);
444
445 m_fbo = 0;
446 }
447
448 if (m_rbo)
449 {
450 gl.deleteRenderbuffers(1, &m_rbo);
451
452 m_rbo = 0;
453 }
454
455 if (m_po)
456 {
457 gl.deleteProgram(m_po);
458
459 m_po = 0;
460 }
461
462 /* Make default context current. */
463 m_test_context.getRenderContext().makeCurrent();
464
465 /* Cleanup context. */
466 delete m_context;
467 }
468 }
469
470 /** @brief Create render context with CONTEXT_RELEASE_BEHAVIOR set to NONE or CONTEXT_RELEASE_BEHAVIOR_FLUSH.
471 *
472 * @return Render context pointer if creation succeeded, DE_NULL otherwise.
473 */
createContext(bool shall_flush_on_release)474 void gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::createContext(bool shall_flush_on_release)
475 {
476 /* Get current platform.*/
477 glu::Platform &platform = dynamic_cast<glu::Platform &>(m_test_context.getTestContext().getPlatform());
478
479 /* Get context related attributes needed to create no-flush context. */
480 const int *attributes = DE_NULL;
481
482 if (!shall_flush_on_release)
483 {
484 attributes = platform.getContextFlushControlContextAttributes();
485 }
486
487 /* Proceed only if it is possible to make no-flush context. */
488 glu::ContextType renderContextType = m_test_context.getRenderContext().getType();
489
490 /* Create no-flush context. */
491 m_context = platform.createRenderContext(renderContextType, m_test_context.getTestContext().getCommandLine(),
492 0 /* shared_context */, attributes);
493 }
494
495 /** @brief Create RGBA8 framebuffer with attached renderbuffer.
496 */
createView()497 void gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::createView()
498 {
499 /* Shortcut for GL functionality. */
500 const glw::Functions &gl = m_context->getFunctions();
501
502 /* Prepare framebuffer. */
503 gl.clearColor(0.f, 0.f, 0.f, 1.f);
504 GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor call failed.");
505
506 gl.genFramebuffers(1, &m_fbo);
507 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers call failed.");
508
509 gl.genRenderbuffers(1, &m_rbo);
510 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers call failed.");
511
512 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
513 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer call failed.");
514
515 gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo);
516 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer call failed.");
517
518 gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, s_view_size, s_view_size);
519 GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage call failed.");
520
521 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo);
522 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer call failed.");
523
524 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
525 {
526 throw 0;
527 }
528
529 gl.viewport(0, 0, s_view_size, s_view_size);
530 GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport call failed.");
531 }
532
533 /** @brief Create and bind empty vertex array object.
534 */
createGeometry()535 void gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::createGeometry()
536 {
537 /* Shortcut for GL functionality. */
538 const glw::Functions &gl = m_context->getFunctions();
539
540 /* Create and bind vertex array. */
541 gl.genVertexArrays(1, &m_vao);
542 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
543
544 gl.bindVertexArray(m_vao);
545 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
546 }
547
548 /** @brief Compile and link shader program.
549 */
createProgram()550 void gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::createProgram()
551 {
552 /* Shortcut for GL functionality. */
553 const glw::Functions &gl = m_context->getFunctions();
554
555 struct Shader
556 {
557 glw::GLchar const *const source;
558 glw::GLenum const type;
559 glw::GLuint id;
560 } shader[] = {{s_vertex_shader, GL_VERTEX_SHADER, 0}, {s_fragment_shader, GL_FRAGMENT_SHADER, 0}};
561
562 glw::GLuint const shader_count = sizeof(shader) / sizeof(shader[0]);
563
564 try
565 {
566 /* Create program. */
567 m_po = gl.createProgram();
568 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram call failed.");
569
570 /* Shader compilation. */
571
572 for (glw::GLuint i = 0; i < shader_count; ++i)
573 {
574 if (DE_NULL != shader[i].source)
575 {
576 shader[i].id = gl.createShader(shader[i].type);
577
578 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader call failed.");
579
580 gl.attachShader(m_po, shader[i].id);
581
582 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader call failed.");
583
584 gl.shaderSource(shader[i].id, 1, &(shader[i].source), NULL);
585
586 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource call failed.");
587
588 gl.compileShader(shader[i].id);
589
590 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader call failed.");
591
592 glw::GLint status = GL_FALSE;
593
594 gl.getShaderiv(shader[i].id, GL_COMPILE_STATUS, &status);
595 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed.");
596
597 if (GL_FALSE == status)
598 {
599 throw 0;
600 }
601 }
602 }
603
604 /* Link. */
605 gl.linkProgram(m_po);
606
607 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed.");
608
609 glw::GLint status = GL_FALSE;
610
611 gl.getProgramiv(m_po, GL_LINK_STATUS, &status);
612
613 if (GL_TRUE == status)
614 {
615 for (glw::GLuint i = 0; i < shader_count; ++i)
616 {
617 if (shader[i].id)
618 {
619 gl.detachShader(m_po, shader[i].id);
620
621 GLU_EXPECT_NO_ERROR(gl.getError(), "glDetachShader call failed.");
622 }
623 }
624 }
625 else
626 {
627 throw 0;
628 }
629 }
630 catch (...)
631 {
632 if (m_po)
633 {
634 gl.deleteProgram(m_po);
635
636 m_po = 0;
637 }
638 }
639
640 for (glw::GLuint i = 0; i < shader_count; ++i)
641 {
642 if (0 != shader[i].id)
643 {
644 gl.deleteShader(shader[i].id);
645
646 shader[i].id = 0;
647 }
648 }
649 }
650
651 const glw::GLuint gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::s_view_size = 256;
652
653 const glw::GLchar gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::s_vertex_shader[] =
654 "#version 130\n"
655 "\n"
656 "void main()\n"
657 "{\n"
658 " switch(gl_VertexID % 4)\n"
659 " {\n"
660 " case 0:\n"
661 " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
662 " break;\n"
663 " case 1:\n"
664 " gl_Position = vec4( 1.0, -1.0, 0.0, 1.0);\n"
665 " break;\n"
666 " case 2:\n"
667 " gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n"
668 " break;\n"
669 " case 3:\n"
670 " gl_Position = vec4( 1.0, 1.0, 0.0, 1.0);\n"
671 " break;\n"
672 " }\n"
673 "}\n";
674
675 const glw::GLchar gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::s_fragment_shader[] =
676 "#version 130\n"
677 "\n"
678 "out vec4 pixel;\n"
679 "\n"
680 "void main()\n"
681 "{\n"
682 " pixel = vec4(1.0);\n"
683 "}\n";
684