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