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() << tcu::TestLog::Message
120 << "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() << tcu::TestLog::Message
281 << "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 << "The running time of no-flush context switches has been slower than flush "
305 "behavior context switching case. "
306 << "This is not expected from quality implementation." << tcu::TestLog::EndMessage;
307
308 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Quality warning.");
309 }
310 }
311
312 return STOP;
313 }
314
315 /** @brief This function measures time of loop consisting of draw and switch context,
316 * which shall or shall not flush on switch.
317 *
318 * The test is based on KHR_context_flush_control extension overview, that the main reason
319 * for no-flush context is to increase the performance of the implementation.
320 *
321 * @param [in] shall_flush_on_release Flag indicating that contexts shall flush when switched.
322 *
323 * @return Run-time of the test loop.
324 */
testTime(bool shall_flush_on_release)325 glw::GLfloat gl4cts::ContextFlushControl::FunctionalTest::testTime(bool shall_flush_on_release)
326 {
327 /* Create two contexts to be switched during test. */
328 DrawSetup draw_context_setup[2] = { DrawSetup(m_context, shall_flush_on_release),
329 DrawSetup(m_context, shall_flush_on_release) };
330
331 /* Check starting time. */
332 deUint64 start_time = deGetMicroseconds();
333
334 /* Loop over draw-switch context. */
335 for (glw::GLuint i = 0; i < 1024; ++i)
336 {
337 draw_context_setup[i % 2].makeCurrent();
338 draw_context_setup[i % 2].draw();
339 }
340
341 /* Check end time. */
342 deUint64 end_time = deGetMicroseconds();
343
344 /* Return resulting run-time. */
345 return (glw::GLfloat)(end_time - start_time);
346 }
347
348 /** @brief Make context current.
349 */
makeCurrent()350 void gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::makeCurrent()
351 {
352 /* Switch context to this. */
353 m_context->makeCurrent();
354 }
355
356 /** @brief Use program and draw full screen quad.
357 */
draw()358 void gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::draw()
359 {
360 /* Shortcut for GL functionality. */
361 const glw::Functions& gl = m_context->getFunctions();
362
363 /* Use GLSL program. */
364 gl.useProgram(m_po);
365 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
366
367 /* Clear. */
368 gl.clear(GL_COLOR_BUFFER_BIT);
369 GLU_EXPECT_NO_ERROR(gl.getError(), "glClear call failed.");
370
371 /* Draw. */
372 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4 /* quad */);
373 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays call failed.");
374 }
375
376 /** @brief Draw Setup object constructor.
377 *
378 * The constructor will throw on error.
379 *
380 * @param [in] test_context Test context for platform, logging and switching to default context on destruction.
381 * @param [in] shall_flush_on_release Flag indicating that contexts shall flush when switched.
382 */
DrawSetup(deqp::Context & test_context,bool shall_flush_on_release)383 gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::DrawSetup(deqp::Context& test_context,
384 bool shall_flush_on_release)
385 : m_test_context(test_context), m_fbo(0), m_rbo(0), m_vao(0), m_po(0)
386 {
387 createContext(shall_flush_on_release);
388
389 if (DE_NULL == m_context)
390 {
391 throw 0;
392 }
393
394 createGeometry();
395
396 if (0 == m_vao)
397 {
398 throw 0;
399 }
400
401 createView();
402
403 if ((0 == m_fbo) || (0 == m_rbo))
404 {
405 throw 0;
406 }
407
408 createProgram();
409
410 if (0 == m_po)
411 {
412 throw 0;
413 }
414 }
415
416 /** @brief Draw Setup object destructor.
417 */
~DrawSetup()418 gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::~DrawSetup()
419 {
420 if (m_context)
421 {
422 /* Make sure context is current. */
423 makeCurrent();
424
425 /* Shortcut for GL functionality. */
426 const glw::Functions& gl = m_context->getFunctions();
427
428 /* Cleanup. */
429 if (m_vao)
430 {
431 gl.deleteVertexArrays(1, &m_vao);
432
433 m_vao = 0;
434 }
435
436 if (m_fbo)
437 {
438 gl.deleteFramebuffers(1, &m_fbo);
439
440 m_fbo = 0;
441 }
442
443 if (m_rbo)
444 {
445 gl.deleteRenderbuffers(1, &m_rbo);
446
447 m_rbo = 0;
448 }
449
450 if (m_po)
451 {
452 gl.deleteProgram(m_po);
453
454 m_po = 0;
455 }
456
457 /* Make default context current. */
458 m_test_context.getRenderContext().makeCurrent();
459
460 /* Cleanup context. */
461 delete m_context;
462 }
463 }
464
465 /** @brief Create render context with CONTEXT_RELEASE_BEHAVIOR set to NONE or CONTEXT_RELEASE_BEHAVIOR_FLUSH.
466 *
467 * @return Render context pointer if creation succeeded, DE_NULL otherwise.
468 */
createContext(bool shall_flush_on_release)469 void gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::createContext(bool shall_flush_on_release)
470 {
471 /* Get current platform.*/
472 glu::Platform& platform = dynamic_cast<glu::Platform&>(m_test_context.getTestContext().getPlatform());
473
474 /* Get context related attributes needed to create no-flush context. */
475 const int* attributes = DE_NULL;
476
477 if (!shall_flush_on_release)
478 {
479 attributes = platform.getContextFlushControlContextAttributes();
480 }
481
482 /* Proceed only if it is possible to make no-flush context. */
483 glu::ContextType renderContextType = m_test_context.getRenderContext().getType();
484
485 /* Create no-flush context. */
486 m_context = platform.createRenderContext(renderContextType, m_test_context.getTestContext().getCommandLine(),
487 0 /* shared_context */, attributes);
488 }
489
490 /** @brief Create RGBA8 framebuffer with attached renderbuffer.
491 */
createView()492 void gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::createView()
493 {
494 /* Shortcut for GL functionality. */
495 const glw::Functions& gl = m_context->getFunctions();
496
497 /* Prepare framebuffer. */
498 gl.clearColor(0.f, 0.f, 0.f, 1.f);
499 GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor call failed.");
500
501 gl.genFramebuffers(1, &m_fbo);
502 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers call failed.");
503
504 gl.genRenderbuffers(1, &m_rbo);
505 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers call failed.");
506
507 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
508 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer call failed.");
509
510 gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo);
511 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer call failed.");
512
513 gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, s_view_size, s_view_size);
514 GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage call failed.");
515
516 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo);
517 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer call failed.");
518
519 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
520 {
521 throw 0;
522 }
523
524 gl.viewport(0, 0, s_view_size, s_view_size);
525 GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport call failed.");
526 }
527
528 /** @brief Create and bind empty vertex array object.
529 */
createGeometry()530 void gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::createGeometry()
531 {
532 /* Shortcut for GL functionality. */
533 const glw::Functions& gl = m_context->getFunctions();
534
535 /* Create and bind vertex array. */
536 gl.genVertexArrays(1, &m_vao);
537 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
538
539 gl.bindVertexArray(m_vao);
540 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
541 }
542
543 /** @brief Compile and link shader program.
544 */
createProgram()545 void gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::createProgram()
546 {
547 /* Shortcut for GL functionality. */
548 const glw::Functions& gl = m_context->getFunctions();
549
550 struct Shader
551 {
552 glw::GLchar const* const source;
553 glw::GLenum const type;
554 glw::GLuint id;
555 } shader[] = { { s_vertex_shader, GL_VERTEX_SHADER, 0 }, { s_fragment_shader, GL_FRAGMENT_SHADER, 0 } };
556
557 glw::GLuint const shader_count = sizeof(shader) / sizeof(shader[0]);
558
559 try
560 {
561 /* Create program. */
562 m_po = gl.createProgram();
563 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram call failed.");
564
565 /* Shader compilation. */
566
567 for (glw::GLuint i = 0; i < shader_count; ++i)
568 {
569 if (DE_NULL != shader[i].source)
570 {
571 shader[i].id = gl.createShader(shader[i].type);
572
573 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader call failed.");
574
575 gl.attachShader(m_po, shader[i].id);
576
577 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader call failed.");
578
579 gl.shaderSource(shader[i].id, 1, &(shader[i].source), NULL);
580
581 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource call failed.");
582
583 gl.compileShader(shader[i].id);
584
585 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader call failed.");
586
587 glw::GLint status = GL_FALSE;
588
589 gl.getShaderiv(shader[i].id, GL_COMPILE_STATUS, &status);
590 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed.");
591
592 if (GL_FALSE == status)
593 {
594 throw 0;
595 }
596 }
597 }
598
599 /* Link. */
600 gl.linkProgram(m_po);
601
602 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed.");
603
604 glw::GLint status = GL_FALSE;
605
606 gl.getProgramiv(m_po, GL_LINK_STATUS, &status);
607
608 if (GL_TRUE == status)
609 {
610 for (glw::GLuint i = 0; i < shader_count; ++i)
611 {
612 if (shader[i].id)
613 {
614 gl.detachShader(m_po, shader[i].id);
615
616 GLU_EXPECT_NO_ERROR(gl.getError(), "glDetachShader call failed.");
617 }
618 }
619 }
620 else
621 {
622 throw 0;
623 }
624 }
625 catch (...)
626 {
627 if (m_po)
628 {
629 gl.deleteProgram(m_po);
630
631 m_po = 0;
632 }
633 }
634
635 for (glw::GLuint i = 0; i < shader_count; ++i)
636 {
637 if (0 != shader[i].id)
638 {
639 gl.deleteShader(shader[i].id);
640
641 shader[i].id = 0;
642 }
643 }
644 }
645
646 const glw::GLuint gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::s_view_size = 256;
647
648 const glw::GLchar gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::s_vertex_shader[] =
649 "#version 130\n"
650 "\n"
651 "void main()\n"
652 "{\n"
653 " switch(gl_VertexID % 4)\n"
654 " {\n"
655 " case 0:\n"
656 " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
657 " break;\n"
658 " case 1:\n"
659 " gl_Position = vec4( 1.0, -1.0, 0.0, 1.0);\n"
660 " break;\n"
661 " case 2:\n"
662 " gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n"
663 " break;\n"
664 " case 3:\n"
665 " gl_Position = vec4( 1.0, 1.0, 0.0, 1.0);\n"
666 " break;\n"
667 " }\n"
668 "}\n";
669
670 const glw::GLchar gl4cts::ContextFlushControl::FunctionalTest::DrawSetup::s_fragment_shader[] =
671 "#version 130\n"
672 "\n"
673 "out vec4 pixel;\n"
674 "\n"
675 "void main()\n"
676 "{\n"
677 " pixel = vec4(1.0);\n"
678 "}\n";
679