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