• 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 "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