• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 #include "shader_utils.h"
8 
9 #include <cstring>
10 #include <fstream>
11 #include <iostream>
12 #include <vector>
13 
14 namespace
15 {
ReadFileToString(const std::string & source)16 std::string ReadFileToString(const std::string &source)
17 {
18     std::ifstream stream(source.c_str());
19     if (!stream)
20     {
21         std::cerr << "Failed to load shader file: " << source;
22         return "";
23     }
24 
25     std::string result;
26 
27     stream.seekg(0, std::ios::end);
28     result.reserve(static_cast<unsigned int>(stream.tellg()));
29     stream.seekg(0, std::ios::beg);
30 
31     result.assign((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
32 
33     return result;
34 }
35 
CompileProgramInternal(const char * vsSource,const char * gsSource,const char * fsSource,const std::function<void (GLuint)> & preLinkCallback)36 GLuint CompileProgramInternal(const char *vsSource,
37                               const char *gsSource,
38                               const char *fsSource,
39                               const std::function<void(GLuint)> &preLinkCallback)
40 {
41     GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
42     GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
43 
44     if (vs == 0 || fs == 0)
45     {
46         glDeleteShader(fs);
47         glDeleteShader(vs);
48         return 0;
49     }
50 
51     GLuint program = glCreateProgram();
52 
53     glAttachShader(program, vs);
54     glDeleteShader(vs);
55 
56     glAttachShader(program, fs);
57     glDeleteShader(fs);
58 
59     GLuint gs = 0;
60 
61     if (strlen(gsSource) > 0)
62     {
63         gs = CompileShader(GL_GEOMETRY_SHADER_EXT, gsSource);
64         if (gs == 0)
65         {
66             glDeleteShader(vs);
67             glDeleteShader(fs);
68             glDeleteProgram(program);
69             return 0;
70         }
71 
72         glAttachShader(program, gs);
73         glDeleteShader(gs);
74     }
75 
76     if (preLinkCallback)
77     {
78         preLinkCallback(program);
79     }
80 
81     glLinkProgram(program);
82 
83     return CheckLinkStatusAndReturnProgram(program, true);
84 }
85 }  // namespace
86 
CompileShader(GLenum type,const char * source)87 GLuint CompileShader(GLenum type, const char *source)
88 {
89     GLuint shader = glCreateShader(type);
90 
91     const char *sourceArray[1] = {source};
92     glShaderSource(shader, 1, sourceArray, nullptr);
93     glCompileShader(shader);
94 
95     GLint compileResult;
96     glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
97 
98     if (compileResult == 0)
99     {
100         GLint infoLogLength;
101         glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
102 
103         // Info log length includes the null terminator, so 1 means that the info log is an empty
104         // string.
105         if (infoLogLength > 1)
106         {
107             std::vector<GLchar> infoLog(infoLogLength);
108             glGetShaderInfoLog(shader, static_cast<GLsizei>(infoLog.size()), nullptr, &infoLog[0]);
109             std::cerr << "shader compilation failed: " << &infoLog[0];
110         }
111         else
112         {
113             std::cerr << "shader compilation failed. <Empty log message>";
114         }
115 
116         std::cerr << std::endl;
117 
118         glDeleteShader(shader);
119         shader = 0;
120     }
121 
122     return shader;
123 }
124 
CompileShaderFromFile(GLenum type,const std::string & sourcePath)125 GLuint CompileShaderFromFile(GLenum type, const std::string &sourcePath)
126 {
127     std::string source = ReadFileToString(sourcePath);
128     if (source.empty())
129     {
130         return 0;
131     }
132 
133     return CompileShader(type, source.c_str());
134 }
135 
CheckLinkStatusAndReturnProgram(GLuint program,bool outputErrorMessages)136 GLuint CheckLinkStatusAndReturnProgram(GLuint program, bool outputErrorMessages)
137 {
138     if (glGetError() != GL_NO_ERROR)
139         return 0;
140 
141     GLint linkStatus;
142     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
143     if (linkStatus == 0)
144     {
145         if (outputErrorMessages)
146         {
147             GLint infoLogLength;
148             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
149 
150             // Info log length includes the null terminator, so 1 means that the info log is an
151             // empty string.
152             if (infoLogLength > 1)
153             {
154                 std::vector<GLchar> infoLog(infoLogLength);
155                 glGetProgramInfoLog(program, static_cast<GLsizei>(infoLog.size()), nullptr,
156                                     &infoLog[0]);
157 
158                 std::cerr << "program link failed: " << &infoLog[0];
159             }
160             else
161             {
162                 std::cerr << "program link failed. <Empty log message>";
163             }
164         }
165 
166         glDeleteProgram(program);
167         return 0;
168     }
169 
170     return program;
171 }
172 
CompileProgramWithTransformFeedback(const char * vsSource,const char * fsSource,const std::vector<std::string> & transformFeedbackVaryings,GLenum bufferMode)173 GLuint CompileProgramWithTransformFeedback(
174     const char *vsSource,
175     const char *fsSource,
176     const std::vector<std::string> &transformFeedbackVaryings,
177     GLenum bufferMode)
178 {
179     auto preLink = [&](GLuint program) {
180         if (transformFeedbackVaryings.size() > 0)
181         {
182             std::vector<const char *> constCharTFVaryings;
183 
184             for (const std::string &transformFeedbackVarying : transformFeedbackVaryings)
185             {
186                 constCharTFVaryings.push_back(transformFeedbackVarying.c_str());
187             }
188 
189             glTransformFeedbackVaryings(program,
190                                         static_cast<GLsizei>(transformFeedbackVaryings.size()),
191                                         &constCharTFVaryings[0], bufferMode);
192         }
193     };
194 
195     return CompileProgramInternal(vsSource, "", fsSource, preLink);
196 }
197 
CompileProgram(const char * vsSource,const char * fsSource)198 GLuint CompileProgram(const char *vsSource, const char *fsSource)
199 {
200     return CompileProgramInternal(vsSource, "", fsSource, nullptr);
201 }
202 
CompileProgram(const char * vsSource,const char * fsSource,const std::function<void (GLuint)> & preLinkCallback)203 GLuint CompileProgram(const char *vsSource,
204                       const char *fsSource,
205                       const std::function<void(GLuint)> &preLinkCallback)
206 {
207     return CompileProgramInternal(vsSource, "", fsSource, preLinkCallback);
208 }
209 
CompileProgramWithGS(const char * vsSource,const char * gsSource,const char * fsSource)210 GLuint CompileProgramWithGS(const char *vsSource, const char *gsSource, const char *fsSource)
211 {
212     return CompileProgramInternal(vsSource, gsSource, fsSource, nullptr);
213 }
214 
CompileProgramFromFiles(const std::string & vsPath,const std::string & fsPath)215 GLuint CompileProgramFromFiles(const std::string &vsPath, const std::string &fsPath)
216 {
217     std::string vsSource = ReadFileToString(vsPath);
218     std::string fsSource = ReadFileToString(fsPath);
219     if (vsSource.empty() || fsSource.empty())
220     {
221         return 0;
222     }
223 
224     return CompileProgram(vsSource.c_str(), fsSource.c_str());
225 }
226 
CompileComputeProgram(const char * csSource,bool outputErrorMessages)227 GLuint CompileComputeProgram(const char *csSource, bool outputErrorMessages)
228 {
229     GLuint program = glCreateProgram();
230 
231     GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
232     if (cs == 0)
233     {
234         glDeleteProgram(program);
235         return 0;
236     }
237 
238     glAttachShader(program, cs);
239 
240     glLinkProgram(program);
241 
242     return CheckLinkStatusAndReturnProgram(program, outputErrorMessages);
243 }
244 
LoadBinaryProgramOES(const std::vector<uint8_t> & binary,GLenum binaryFormat)245 GLuint LoadBinaryProgramOES(const std::vector<uint8_t> &binary, GLenum binaryFormat)
246 {
247     GLuint program = glCreateProgram();
248     glProgramBinaryOES(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
249     return CheckLinkStatusAndReturnProgram(program, true);
250 }
251 
LoadBinaryProgramES3(const std::vector<uint8_t> & binary,GLenum binaryFormat)252 GLuint LoadBinaryProgramES3(const std::vector<uint8_t> &binary, GLenum binaryFormat)
253 {
254     GLuint program = glCreateProgram();
255     glProgramBinary(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
256     return CheckLinkStatusAndReturnProgram(program, true);
257 }
258 
LinkAttachedProgram(GLuint program)259 bool LinkAttachedProgram(GLuint program)
260 {
261     glLinkProgram(program);
262     return (CheckLinkStatusAndReturnProgram(program, true) != 0);
263 }
264 
265 namespace angle
266 {
267 
268 namespace essl1_shaders
269 {
270 
PositionAttrib()271 const char *PositionAttrib()
272 {
273     return "a_position";
274 }
ColorUniform()275 const char *ColorUniform()
276 {
277     return "u_color";
278 }
279 
Texture2DUniform()280 const char *Texture2DUniform()
281 {
282     return "u_tex2D";
283 }
284 
285 namespace vs
286 {
287 
288 // A shader that sets gl_Position to zero.
Zero()289 const char *Zero()
290 {
291     return R"(void main()
292 {
293     gl_Position = vec4(0);
294 })";
295 }
296 
297 // A shader that sets gl_Position to attribute a_position.
Simple()298 const char *Simple()
299 {
300     return R"(precision highp float;
301 attribute vec4 a_position;
302 
303 void main()
304 {
305     gl_Position = a_position;
306 })";
307 }
308 
309 // A shader that simply passes through attribute a_position, setting it to gl_Position and varying
310 // v_position.
Passthrough()311 const char *Passthrough()
312 {
313     return R"(precision highp float;
314 attribute vec4 a_position;
315 varying vec4 v_position;
316 
317 void main()
318 {
319     gl_Position = a_position;
320     v_position = a_position;
321 })";
322 }
323 
324 // A shader that simply passes through attribute a_position, setting it to gl_Position and varying
325 // texcoord.
Texture2D()326 const char *Texture2D()
327 {
328     return R"(precision highp float;
329 attribute vec4 a_position;
330 varying vec2 v_texCoord;
331 
332 void main()
333 {
334     gl_Position = vec4(a_position.xy, 0.0, 1.0);
335     v_texCoord = a_position.xy * 0.5 + vec2(0.5);
336 })";
337 }
338 
339 }  // namespace vs
340 
341 namespace fs
342 {
343 
344 // A shader that renders a simple checker pattern of red and green. X axis and y axis separate the
345 // different colors. Needs varying v_position.
Checkered()346 const char *Checkered()
347 {
348     return R"(precision highp float;
349 varying vec4 v_position;
350 
351 void main()
352 {
353     if (v_position.x * v_position.y > 0.0)
354     {
355         gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
356     }
357     else
358     {
359         gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
360     }
361 })";
362 }
363 
364 // A shader that fills with color taken from uniform named "color".
UniformColor()365 const char *UniformColor()
366 {
367     return R"(uniform mediump vec4 u_color;
368 void main(void)
369 {
370     gl_FragColor = u_color;
371 })";
372 }
373 
374 // A shader that fills with 100% opaque red.
Red()375 const char *Red()
376 {
377     return R"(precision mediump float;
378 
379 void main()
380 {
381     gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
382 })";
383 }
384 
385 // A shader that fills with 100% opaque green.
Green()386 const char *Green()
387 {
388     return R"(precision mediump float;
389 
390 void main()
391 {
392     gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
393 })";
394 }
395 
396 // A shader that fills with 100% opaque blue.
Blue()397 const char *Blue()
398 {
399     return R"(precision mediump float;
400 
401 void main()
402 {
403     gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
404 })";
405 }
406 
407 // A shader that samples the texture.
Texture2D()408 const char *Texture2D()
409 {
410     return R"(precision mediump float;
411 uniform sampler2D u_tex;
412 varying vec2 v_texCoord;
413 
414 void main()
415 {
416     gl_FragColor = texture2D(u_tex, v_texCoord);
417 })";
418 }
419 
420 }  // namespace fs
421 }  // namespace essl1_shaders
422 
423 namespace essl3_shaders
424 {
425 
PositionAttrib()426 const char *PositionAttrib()
427 {
428     return "a_position";
429 }
430 
431 namespace vs
432 {
433 
434 // A shader that sets gl_Position to zero.
Zero()435 const char *Zero()
436 {
437     return R"(#version 300 es
438 void main()
439 {
440     gl_Position = vec4(0);
441 })";
442 }
443 
444 // A shader that sets gl_Position to attribute a_position.
Simple()445 const char *Simple()
446 {
447     return R"(#version 300 es
448 in vec4 a_position;
449 void main()
450 {
451     gl_Position = a_position;
452 })";
453 }
454 
455 // A shader that simply passes through attribute a_position, setting it to gl_Position and varying
456 // v_position.
Passthrough()457 const char *Passthrough()
458 {
459     return R"(#version 300 es
460 in vec4 a_position;
461 out vec4 v_position;
462 void main()
463 {
464     gl_Position = a_position;
465     v_position = a_position;
466 })";
467 }
468 
469 }  // namespace vs
470 
471 namespace fs
472 {
473 
474 // A shader that fills with 100% opaque red.
Red()475 const char *Red()
476 {
477     return R"(#version 300 es
478 precision highp float;
479 out vec4 my_FragColor;
480 void main()
481 {
482     my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
483 })";
484 }
485 
486 // A shader that fills with 100% opaque green.
Green()487 const char *Green()
488 {
489     return R"(#version 300 es
490 precision highp float;
491 out vec4 my_FragColor;
492 void main()
493 {
494     my_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
495 })";
496 }
497 
498 // A shader that fills with 100% opaque blue.
Blue()499 const char *Blue()
500 {
501     return R"(#version 300 es
502 precision highp float;
503 out vec4 my_FragColor;
504 void main()
505 {
506     my_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
507 })";
508 }
509 
510 }  // namespace fs
511 }  // namespace essl3_shaders
512 
513 namespace essl31_shaders
514 {
515 
PositionAttrib()516 const char *PositionAttrib()
517 {
518     return "a_position";
519 }
520 
521 namespace vs
522 {
523 
524 // A shader that sets gl_Position to zero.
Zero()525 const char *Zero()
526 {
527     return R"(#version 310 es
528 void main()
529 {
530     gl_Position = vec4(0);
531 })";
532 }
533 
534 // A shader that sets gl_Position to attribute a_position.
Simple()535 const char *Simple()
536 {
537     return R"(#version 310 es
538 in vec4 a_position;
539 void main()
540 {
541     gl_Position = a_position;
542 })";
543 }
544 
545 // A shader that simply passes through attribute a_position, setting it to gl_Position and varying
546 // v_position.
Passthrough()547 const char *Passthrough()
548 {
549     return R"(#version 310 es
550 in vec4 a_position;
551 out vec4 v_position;
552 void main()
553 {
554     gl_Position = a_position;
555     v_position = a_position;
556 })";
557 }
558 
559 }  // namespace vs
560 
561 namespace fs
562 {
563 
564 // A shader that fills with 100% opaque red.
Red()565 const char *Red()
566 {
567     return R"(#version 310 es
568 precision highp float;
569 out vec4 my_FragColor;
570 void main()
571 {
572     my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
573 })";
574 }
575 
576 }  // namespace fs
577 }  // namespace essl31_shaders
578 }  // namespace angle
579