• 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 
GetProgramShader(GLuint program,GLint requestedType)167 GLuint GetProgramShader(GLuint program, GLint requestedType)
168 {
169     static constexpr GLsizei kMaxShaderCount = 16;
170     GLuint attachedShaders[kMaxShaderCount]  = {0u};
171     GLsizei count                            = 0;
172     glGetAttachedShaders(program, kMaxShaderCount, &count, attachedShaders);
173     for (int i = 0; i < count; ++i)
174     {
175         GLint type = 0;
176         glGetShaderiv(attachedShaders[i], GL_SHADER_TYPE, &type);
177         if (type == requestedType)
178         {
179             return attachedShaders[i];
180         }
181     }
182 
183     return 0;
184 }
185 
CompileProgramWithTransformFeedback(const char * vsSource,const char * fsSource,const std::vector<std::string> & transformFeedbackVaryings,GLenum bufferMode)186 GLuint CompileProgramWithTransformFeedback(
187     const char *vsSource,
188     const char *fsSource,
189     const std::vector<std::string> &transformFeedbackVaryings,
190     GLenum bufferMode)
191 {
192     auto preLink = [&](GLuint program) {
193         if (transformFeedbackVaryings.size() > 0)
194         {
195             std::vector<const char *> constCharTFVaryings;
196 
197             for (const std::string &transformFeedbackVarying : transformFeedbackVaryings)
198             {
199                 constCharTFVaryings.push_back(transformFeedbackVarying.c_str());
200             }
201 
202             glTransformFeedbackVaryings(program,
203                                         static_cast<GLsizei>(transformFeedbackVaryings.size()),
204                                         &constCharTFVaryings[0], bufferMode);
205         }
206     };
207 
208     return CompileProgramInternal(vsSource, "", fsSource, preLink);
209 }
210 
CompileProgram(const char * vsSource,const char * fsSource)211 GLuint CompileProgram(const char *vsSource, const char *fsSource)
212 {
213     return CompileProgramInternal(vsSource, "", fsSource, nullptr);
214 }
215 
CompileProgram(const char * vsSource,const char * fsSource,const std::function<void (GLuint)> & preLinkCallback)216 GLuint CompileProgram(const char *vsSource,
217                       const char *fsSource,
218                       const std::function<void(GLuint)> &preLinkCallback)
219 {
220     return CompileProgramInternal(vsSource, "", fsSource, preLinkCallback);
221 }
222 
CompileProgramWithGS(const char * vsSource,const char * gsSource,const char * fsSource)223 GLuint CompileProgramWithGS(const char *vsSource, const char *gsSource, const char *fsSource)
224 {
225     return CompileProgramInternal(vsSource, gsSource, fsSource, nullptr);
226 }
227 
CompileProgramFromFiles(const std::string & vsPath,const std::string & fsPath)228 GLuint CompileProgramFromFiles(const std::string &vsPath, const std::string &fsPath)
229 {
230     std::string vsSource;
231     if (!ReadEntireFile(vsPath, &vsSource))
232     {
233         std::cerr << "Error reading shader: " << vsPath << "\n";
234         return 0;
235     }
236 
237     std::string fsSource;
238     if (!ReadEntireFile(fsPath, &fsSource))
239     {
240         std::cerr << "Error reading shader: " << fsPath << "\n";
241         return 0;
242     }
243 
244     return CompileProgram(vsSource.c_str(), fsSource.c_str());
245 }
246 
CompileComputeProgram(const char * csSource,bool outputErrorMessages)247 GLuint CompileComputeProgram(const char *csSource, bool outputErrorMessages)
248 {
249     GLuint program = glCreateProgram();
250 
251     GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
252     if (cs == 0)
253     {
254         glDeleteProgram(program);
255         return 0;
256     }
257 
258     glAttachShader(program, cs);
259 
260     glLinkProgram(program);
261 
262     return CheckLinkStatusAndReturnProgram(program, outputErrorMessages);
263 }
264 
LoadBinaryProgramOES(const std::vector<uint8_t> & binary,GLenum binaryFormat)265 GLuint LoadBinaryProgramOES(const std::vector<uint8_t> &binary, GLenum binaryFormat)
266 {
267     GLuint program = glCreateProgram();
268     glProgramBinaryOES(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
269     return CheckLinkStatusAndReturnProgram(program, true);
270 }
271 
LoadBinaryProgramES3(const std::vector<uint8_t> & binary,GLenum binaryFormat)272 GLuint LoadBinaryProgramES3(const std::vector<uint8_t> &binary, GLenum binaryFormat)
273 {
274     GLuint program = glCreateProgram();
275     glProgramBinary(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
276     return CheckLinkStatusAndReturnProgram(program, true);
277 }
278 
LinkAttachedProgram(GLuint program)279 bool LinkAttachedProgram(GLuint program)
280 {
281     glLinkProgram(program);
282     return (CheckLinkStatusAndReturnProgram(program, true) != 0);
283 }
284 
285 namespace angle
286 {
287 
288 namespace essl1_shaders
289 {
290 
PositionAttrib()291 const char *PositionAttrib()
292 {
293     return "a_position";
294 }
ColorUniform()295 const char *ColorUniform()
296 {
297     return "u_color";
298 }
299 
Texture2DUniform()300 const char *Texture2DUniform()
301 {
302     return "u_tex2D";
303 }
304 
305 namespace vs
306 {
307 
308 // A shader that sets gl_Position to zero.
Zero()309 const char *Zero()
310 {
311     return R"(void main()
312 {
313     gl_Position = vec4(0);
314 })";
315 }
316 
317 // A shader that sets gl_Position to attribute a_position.
Simple()318 const char *Simple()
319 {
320     return R"(precision highp float;
321 attribute vec4 a_position;
322 
323 void main()
324 {
325     gl_Position = a_position;
326 })";
327 }
328 
329 // A shader that simply passes through attribute a_position, setting it to gl_Position and varying
330 // v_position.
Passthrough()331 const char *Passthrough()
332 {
333     return R"(precision highp float;
334 attribute vec4 a_position;
335 varying vec4 v_position;
336 
337 void main()
338 {
339     gl_Position = a_position;
340     v_position = a_position;
341 })";
342 }
343 
344 // A shader that simply passes through attribute a_position, setting it to gl_Position and varying
345 // texcoord.
Texture2D()346 const char *Texture2D()
347 {
348     return R"(precision highp float;
349 attribute vec4 a_position;
350 varying vec2 v_texCoord;
351 
352 void main()
353 {
354     gl_Position = vec4(a_position.xy, 0.0, 1.0);
355     v_texCoord = a_position.xy * 0.5 + vec2(0.5);
356 })";
357 }
358 
359 }  // namespace vs
360 
361 namespace fs
362 {
363 
364 // A shader that renders a simple checker pattern of red and green. X axis and y axis separate the
365 // different colors. Needs varying v_position.
Checkered()366 const char *Checkered()
367 {
368     return R"(precision highp float;
369 varying vec4 v_position;
370 
371 void main()
372 {
373     if (v_position.x * v_position.y > 0.0)
374     {
375         gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
376     }
377     else
378     {
379         gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
380     }
381 })";
382 }
383 
384 // A shader that fills with color taken from uniform named "color".
UniformColor()385 const char *UniformColor()
386 {
387     return R"(uniform mediump vec4 u_color;
388 void main(void)
389 {
390     gl_FragColor = u_color;
391 })";
392 }
393 
394 // A shader that fills with 100% opaque red.
Red()395 const char *Red()
396 {
397     return R"(precision mediump float;
398 
399 void main()
400 {
401     gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
402 })";
403 }
404 
405 // A shader that fills with 100% opaque green.
Green()406 const char *Green()
407 {
408     return R"(precision mediump float;
409 
410 void main()
411 {
412     gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
413 })";
414 }
415 
416 // A shader that fills with 100% opaque blue.
Blue()417 const char *Blue()
418 {
419     return R"(precision mediump float;
420 
421 void main()
422 {
423     gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
424 })";
425 }
426 
427 // A shader that samples the texture.
Texture2D()428 const char *Texture2D()
429 {
430     return R"(precision mediump float;
431 uniform sampler2D u_tex2D;
432 varying vec2 v_texCoord;
433 
434 void main()
435 {
436     gl_FragColor = texture2D(u_tex2D, v_texCoord);
437 })";
438 }
439 
440 }  // namespace fs
441 }  // namespace essl1_shaders
442 
443 namespace essl3_shaders
444 {
445 
PositionAttrib()446 const char *PositionAttrib()
447 {
448     return "a_position";
449 }
450 
451 namespace vs
452 {
453 
454 // A shader that sets gl_Position to zero.
Zero()455 const char *Zero()
456 {
457     return R"(#version 300 es
458 void main()
459 {
460     gl_Position = vec4(0);
461 })";
462 }
463 
464 // A shader that sets gl_Position to attribute a_position.
Simple()465 const char *Simple()
466 {
467     return R"(#version 300 es
468 in vec4 a_position;
469 void main()
470 {
471     gl_Position = a_position;
472 })";
473 }
474 
475 // A shader that simply passes through attribute a_position, setting it to gl_Position and varying
476 // v_position.
Passthrough()477 const char *Passthrough()
478 {
479     return R"(#version 300 es
480 in vec4 a_position;
481 out vec4 v_position;
482 void main()
483 {
484     gl_Position = a_position;
485     v_position = a_position;
486 })";
487 }
488 
489 }  // namespace vs
490 
491 namespace fs
492 {
493 
494 // A shader that fills with 100% opaque red.
Red()495 const char *Red()
496 {
497     return R"(#version 300 es
498 precision highp float;
499 out vec4 my_FragColor;
500 void main()
501 {
502     my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
503 })";
504 }
505 
506 // A shader that fills with 100% opaque green.
Green()507 const char *Green()
508 {
509     return R"(#version 300 es
510 precision highp float;
511 out vec4 my_FragColor;
512 void main()
513 {
514     my_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
515 })";
516 }
517 
518 // A shader that fills with 100% opaque blue.
Blue()519 const char *Blue()
520 {
521     return R"(#version 300 es
522 precision highp float;
523 out vec4 my_FragColor;
524 void main()
525 {
526     my_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
527 })";
528 }
529 
530 }  // namespace fs
531 }  // namespace essl3_shaders
532 
533 namespace essl31_shaders
534 {
535 
PositionAttrib()536 const char *PositionAttrib()
537 {
538     return "a_position";
539 }
540 
541 namespace vs
542 {
543 
544 // A shader that sets gl_Position to zero.
Zero()545 const char *Zero()
546 {
547     return R"(#version 310 es
548 void main()
549 {
550     gl_Position = vec4(0);
551 })";
552 }
553 
554 // A shader that sets gl_Position to attribute a_position.
Simple()555 const char *Simple()
556 {
557     return R"(#version 310 es
558 in vec4 a_position;
559 void main()
560 {
561     gl_Position = a_position;
562 })";
563 }
564 
565 // A shader that simply passes through attribute a_position, setting it to gl_Position and varying
566 // v_position.
Passthrough()567 const char *Passthrough()
568 {
569     return R"(#version 310 es
570 in vec4 a_position;
571 out vec4 v_position;
572 void main()
573 {
574     gl_Position = a_position;
575     v_position = a_position;
576 })";
577 }
578 
579 }  // namespace vs
580 
581 namespace fs
582 {
583 
584 // A shader that fills with 100% opaque red.
Red()585 const char *Red()
586 {
587     return R"(#version 310 es
588 precision highp float;
589 out vec4 my_FragColor;
590 void main()
591 {
592     my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
593 })";
594 }
595 
596 // A shader that fills with 100% opaque green.
Green()597 const char *Green()
598 {
599     return R"(#version 310 es
600 precision highp float;
601 out vec4 my_FragColor;
602 void main()
603 {
604     my_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
605 })";
606 }
607 
608 }  // namespace fs
609 }  // namespace essl31_shaders
610 }  // namespace angle
611