blob: d42507719f0ebfa80889522bb10aaa0d50ef799b [file] [log] [blame]
Geoff Lang49be2ad2014-02-28 13:05:51 -05001//
2// Copyright (c) 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 <vector>
10#include <iostream>
Geoff Lang712e3f42014-03-03 11:14:15 -050011#include <fstream>
12
13static std::string ReadFileToString(const std::string &source)
14{
Corentin Wallezf0ca9a02015-09-14 11:53:10 -070015 std::ifstream stream(source.c_str());
Geoff Lang712e3f42014-03-03 11:14:15 -050016 if (!stream)
17 {
18 std::cerr << "Failed to load shader file: " << source;
19 return "";
20 }
21
22 std::string result;
23
24 stream.seekg(0, std::ios::end);
Minmin Gong794e0002015-04-07 18:31:54 -070025 result.reserve(static_cast<unsigned int>(stream.tellg()));
Geoff Lang712e3f42014-03-03 11:14:15 -050026 stream.seekg(0, std::ios::beg);
27
28 result.assign((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
29
30 return result;
31}
Geoff Lang49be2ad2014-02-28 13:05:51 -050032
33GLuint CompileShader(GLenum type, const std::string &source)
34{
35 GLuint shader = glCreateShader(type);
36
37 const char *sourceArray[1] = { source.c_str() };
Yunchao Hef81ce4a2017-04-24 10:49:17 +080038 glShaderSource(shader, 1, sourceArray, nullptr);
Geoff Lang49be2ad2014-02-28 13:05:51 -050039 glCompileShader(shader);
40
41 GLint compileResult;
42 glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
43
44 if (compileResult == 0)
45 {
46 GLint infoLogLength;
47 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
48
Olli Etuaho67946762016-03-08 15:43:55 +020049 // Info log length includes the null terminator, so 1 means that the info log is an empty
50 // string.
51 if (infoLogLength > 1)
Jamie Madill90c253a2015-12-15 15:14:08 -050052 {
53 std::vector<GLchar> infoLog(infoLogLength);
Yunchao Hef81ce4a2017-04-24 10:49:17 +080054 glGetShaderInfoLog(shader, static_cast<GLsizei>(infoLog.size()), nullptr, &infoLog[0]);
Jamie Madill90c253a2015-12-15 15:14:08 -050055 std::cerr << "shader compilation failed: " << &infoLog[0];
56 }
57 else
58 {
59 std::cerr << "shader compilation failed. <Empty log message>";
60 }
Geoff Lang49be2ad2014-02-28 13:05:51 -050061
Jamie Madillbd044ed2017-06-05 12:59:21 -040062 std::cerr << std::endl;
63
Geoff Lang49be2ad2014-02-28 13:05:51 -050064 glDeleteShader(shader);
65 shader = 0;
66 }
67
68 return shader;
69}
70
Geoff Lang712e3f42014-03-03 11:14:15 -050071GLuint CompileShaderFromFile(GLenum type, const std::string &sourcePath)
72{
73 std::string source = ReadFileToString(sourcePath);
74 if (source.empty())
75 {
76 return 0;
77 }
78
79 return CompileShader(type, source);
80}
81
Martin Radev4c4c8e72016-08-04 12:25:34 +030082GLuint CheckLinkStatusAndReturnProgram(GLuint program, bool outputErrorMessages)
83{
Jamie Madilla7d12dc2016-12-13 15:08:19 -050084 if (glGetError() != GL_NO_ERROR)
85 return 0;
86
Martin Radev4c4c8e72016-08-04 12:25:34 +030087 GLint linkStatus;
88 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
89 if (linkStatus == 0)
90 {
91 if (outputErrorMessages)
92 {
93 GLint infoLogLength;
94 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
95
96 // Info log length includes the null terminator, so 1 means that the info log is an
97 // empty string.
98 if (infoLogLength > 1)
99 {
100 std::vector<GLchar> infoLog(infoLogLength);
101 glGetProgramInfoLog(program, static_cast<GLsizei>(infoLog.size()), nullptr,
102 &infoLog[0]);
103
104 std::cerr << "program link failed: " << &infoLog[0];
105 }
106 else
107 {
108 std::cerr << "program link failed. <Empty log message>";
109 }
110 }
111
112 glDeleteProgram(program);
113 return 0;
114 }
115
116 return program;
117}
118
Jamie Madillca03b352015-09-02 12:38:13 -0400119GLuint CompileProgramWithTransformFeedback(
120 const std::string &vsSource,
121 const std::string &fsSource,
122 const std::vector<std::string> &transformFeedbackVaryings,
123 GLenum bufferMode)
Geoff Lang49be2ad2014-02-28 13:05:51 -0500124{
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800125 return CompileProgramWithGSAndTransformFeedback(vsSource, "", fsSource,
126 transformFeedbackVaryings, bufferMode);
127}
128
129GLuint CompileProgramWithGSAndTransformFeedback(
130 const std::string &vsSource,
131 const std::string &gsSource,
132 const std::string &fsSource,
133 const std::vector<std::string> &transformFeedbackVaryings,
134 GLenum bufferMode)
135{
Geoff Lang49be2ad2014-02-28 13:05:51 -0500136 GLuint program = glCreateProgram();
137
138 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
139 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
140
141 if (vs == 0 || fs == 0)
142 {
143 glDeleteShader(fs);
144 glDeleteShader(vs);
145 glDeleteProgram(program);
146 return 0;
147 }
148
149 glAttachShader(program, vs);
150 glDeleteShader(vs);
151
152 glAttachShader(program, fs);
153 glDeleteShader(fs);
154
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800155 if (!gsSource.empty())
156 {
157 GLuint gs = CompileShader(GL_GEOMETRY_SHADER_EXT, gsSource);
158 if (gs == 0)
159 {
160 glDeleteShader(vs);
161 glDeleteShader(fs);
162 glDeleteProgram(program);
163 return 0;
164 }
165
166 glAttachShader(program, gs);
167 glDeleteShader(gs);
168 }
169
Jamie Madillca03b352015-09-02 12:38:13 -0400170 if (transformFeedbackVaryings.size() > 0)
171 {
172 std::vector<const char *> constCharTFVaryings;
173
174 for (const std::string &transformFeedbackVarying : transformFeedbackVaryings)
175 {
176 constCharTFVaryings.push_back(transformFeedbackVarying.c_str());
177 }
178
179 glTransformFeedbackVaryings(program, static_cast<GLsizei>(transformFeedbackVaryings.size()),
180 &constCharTFVaryings[0], bufferMode);
181 }
182
Geoff Lang49be2ad2014-02-28 13:05:51 -0500183 glLinkProgram(program);
184
Martin Radev4c4c8e72016-08-04 12:25:34 +0300185 return CheckLinkStatusAndReturnProgram(program, true);
Geoff Lang49be2ad2014-02-28 13:05:51 -0500186}
Geoff Lang712e3f42014-03-03 11:14:15 -0500187
Jamie Madillca03b352015-09-02 12:38:13 -0400188GLuint CompileProgram(const std::string &vsSource, const std::string &fsSource)
189{
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800190 return CompileProgramWithGS(vsSource, "", fsSource);
191}
192
193GLuint CompileProgramWithGS(const std::string &vsSource,
194 const std::string &gsSource,
195 const std::string &fsSource)
196{
Jamie Madillca03b352015-09-02 12:38:13 -0400197 std::vector<std::string> emptyVector;
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800198 return CompileProgramWithGSAndTransformFeedback(vsSource, gsSource, fsSource, emptyVector,
199 GL_NONE);
Jamie Madillca03b352015-09-02 12:38:13 -0400200}
201
Geoff Lang712e3f42014-03-03 11:14:15 -0500202GLuint CompileProgramFromFiles(const std::string &vsPath, const std::string &fsPath)
203{
204 std::string vsSource = ReadFileToString(vsPath);
205 std::string fsSource = ReadFileToString(fsPath);
206 if (vsSource.empty() || fsSource.empty())
207 {
208 return 0;
209 }
210
211 return CompileProgram(vsSource, fsSource);
212}
Martin Radev4c4c8e72016-08-04 12:25:34 +0300213
214GLuint CompileComputeProgram(const std::string &csSource, bool outputErrorMessages)
215{
216 GLuint program = glCreateProgram();
217
218 GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
219 if (cs == 0)
220 {
221 glDeleteProgram(program);
222 return 0;
223 }
224
225 glAttachShader(program, cs);
226
227 glLinkProgram(program);
228
229 return CheckLinkStatusAndReturnProgram(program, outputErrorMessages);
230}
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500231
232GLuint LoadBinaryProgramOES(const std::vector<uint8_t> &binary, GLenum binaryFormat)
233{
234 GLuint program = glCreateProgram();
235 glProgramBinaryOES(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
236 return CheckLinkStatusAndReturnProgram(program, true);
237}
238
239GLuint LoadBinaryProgramES3(const std::vector<uint8_t> &binary, GLenum binaryFormat)
240{
241 GLuint program = glCreateProgram();
242 glProgramBinary(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
243 return CheckLinkStatusAndReturnProgram(program, true);
244}
Jamie Madill401345e2017-08-21 10:52:40 -0400245
246bool LinkAttachedProgram(GLuint program)
247{
248 glLinkProgram(program);
249 return (CheckLinkStatusAndReturnProgram(program, true) != 0);
250}
Olli Etuaho5804dc82018-04-13 14:11:46 +0300251
252namespace angle
253{
254
255namespace essl1_shaders
256{
257
258const char *PositionAttrib()
259{
260 return "a_position";
261}
262const char *ColorUniform()
263{
264 return "u_color";
265}
266
267namespace vs
268{
269
270// A shader that sets gl_Position to zero.
271const char *Zero()
272{
273 return R"(void main()
274{
275 gl_Position = vec4(0);
276})";
277}
278
279// A shader that sets gl_Position to attribute a_position.
280const char *Simple()
281{
282 return R"(precision highp float;
283attribute vec4 a_position;
284
285void main()
286{
287 gl_Position = a_position;
288})";
289}
290
291// A shader that simply passes through attribute a_position, setting it to gl_Position and varying
292// pos.
293const char *Passthrough()
294{
295 return R"(precision highp float;
296attribute vec4 a_position;
297varying vec4 v_position;
298
299void main()
300{
301 gl_Position = a_position;
302 v_position = a_position;
303})";
304}
305
306} // namespace vs
307
308namespace fs
309{
310
311// A shader that renders a simple checker pattern of red and green. X axis and y axis separate the
312// different colors. Needs varying v_position.
313const char *Checkered()
314{
315 return R"(precision highp float;
316varying vec4 v_position;
317
318void main()
319{
320 if (v_position.x * v_position.y > 0.0)
321 {
322 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
323 }
324 else
325 {
326 gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
327 }
328})";
329}
330
331// A shader that fills with color taken from uniform named "color".
332const char *UniformColor()
333{
334 return R"(uniform mediump vec4 u_color;
335void main(void)
336{
337 gl_FragColor = u_color;
338})";
339}
340
341// A shader that fills with 100% opaque red.
342const char *Red()
343{
344 return R"(precision mediump float;
345
346void main()
347{
348 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
349})";
350}
351
352// A shader that fills with 100% opaque blue.
353const char *Blue()
354{
355 return R"(precision mediump float;
356
357void main()
358{
359 gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
360})";
361}
362
363} // namespace fs
364} // namespace essl1_shaders
365
366namespace essl3_shaders
367{
368
369const char *PositionAttrib()
370{
371 return "a_position";
372}
373
374namespace vs
375{
376
377// A shader that sets gl_Position to zero.
378const char *Zero()
379{
380 return R"(#version 300 es
381void main()
382{
383 gl_Position = vec4(0);
384})";
385}
386
387// A shader that sets gl_Position to attribute a_position.
388const char *Simple()
389{
390 return R"(#version 300 es
391in vec4 a_position;
392void main()
393{
394 gl_Position = a_position;
395})";
396}
397
398} // namespace vs
399
400namespace fs
401{
402
403// A shader that fills with 100% opaque red.
404const char *Red()
405{
406 return R"(#version 300 es
407precision highp float;
408out vec4 my_FragColor;
409void main()
410{
411 my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
412})";
413}
414
415} // namespace fs
416} // namespace essl3_shaders
417
418namespace essl31_shaders
419{
420
421const char *PositionAttrib()
422{
423 return "a_position";
424}
425
426namespace vs
427{
428
429// A shader that sets gl_Position to zero.
430const char *Zero()
431{
432 return R"(#version 310 es
433void main()
434{
435 gl_Position = vec4(0);
436})";
437}
438
439// A shader that sets gl_Position to attribute a_position.
440const char *Simple()
441{
442 return R"(#version 310 es
443in vec4 a_position;
444void main()
445{
446 gl_Position = a_position;
447})";
448}
449
450} // namespace vs
451
452namespace fs
453{
454
455// A shader that fills with 100% opaque red.
456const char *Red()
457{
458 return R"(#version 310 es
459precision highp float;
460out vec4 my_FragColor;
461void main()
462{
463 my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
464})";
465}
466
467} // namespace fs
468} // namespace essl31_shaders
469} // namespace angle