blob: 40d469b573cb79d2a35a5073c00ae8cac79af406 [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
jchen107ae70d82018-07-06 13:47:01 +0800129static GLuint CompileAndLinkProgram(const std::string &vsSource,
130 const std::string &gsSource,
131 const std::string &fsSource,
132 const std::vector<std::string> &transformFeedbackVaryings,
133 GLenum bufferMode)
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800134{
Geoff Lang49be2ad2014-02-28 13:05:51 -0500135 GLuint program = glCreateProgram();
136
137 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
138 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
139
140 if (vs == 0 || fs == 0)
141 {
142 glDeleteShader(fs);
143 glDeleteShader(vs);
144 glDeleteProgram(program);
145 return 0;
146 }
147
148 glAttachShader(program, vs);
149 glDeleteShader(vs);
150
151 glAttachShader(program, fs);
152 glDeleteShader(fs);
153
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800154 if (!gsSource.empty())
155 {
156 GLuint gs = CompileShader(GL_GEOMETRY_SHADER_EXT, gsSource);
157 if (gs == 0)
158 {
159 glDeleteShader(vs);
160 glDeleteShader(fs);
161 glDeleteProgram(program);
162 return 0;
163 }
164
165 glAttachShader(program, gs);
166 glDeleteShader(gs);
167 }
168
Jamie Madillca03b352015-09-02 12:38:13 -0400169 if (transformFeedbackVaryings.size() > 0)
170 {
171 std::vector<const char *> constCharTFVaryings;
172
173 for (const std::string &transformFeedbackVarying : transformFeedbackVaryings)
174 {
175 constCharTFVaryings.push_back(transformFeedbackVarying.c_str());
176 }
177
178 glTransformFeedbackVaryings(program, static_cast<GLsizei>(transformFeedbackVaryings.size()),
179 &constCharTFVaryings[0], bufferMode);
180 }
181
Geoff Lang49be2ad2014-02-28 13:05:51 -0500182 glLinkProgram(program);
183
jchen107ae70d82018-07-06 13:47:01 +0800184 return program;
185}
186
187GLuint CompileProgramWithGSAndTransformFeedback(
188 const std::string &vsSource,
189 const std::string &gsSource,
190 const std::string &fsSource,
191 const std::vector<std::string> &transformFeedbackVaryings,
192 GLenum bufferMode)
193{
194 GLuint program =
195 CompileAndLinkProgram(vsSource, gsSource, fsSource, transformFeedbackVaryings, bufferMode);
196 if (program == 0)
197 {
198 return 0;
199 }
Martin Radev4c4c8e72016-08-04 12:25:34 +0300200 return CheckLinkStatusAndReturnProgram(program, true);
Geoff Lang49be2ad2014-02-28 13:05:51 -0500201}
Geoff Lang712e3f42014-03-03 11:14:15 -0500202
Jamie Madillca03b352015-09-02 12:38:13 -0400203GLuint CompileProgram(const std::string &vsSource, const std::string &fsSource)
204{
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800205 return CompileProgramWithGS(vsSource, "", fsSource);
206}
207
jchen107ae70d82018-07-06 13:47:01 +0800208GLuint CompileProgramParallel(const std::string &vsSource, const std::string &fsSource)
209{
210 std::vector<std::string> emptyVector;
211 return CompileAndLinkProgram(vsSource, "", fsSource, emptyVector, GL_NONE);
212}
213
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800214GLuint CompileProgramWithGS(const std::string &vsSource,
215 const std::string &gsSource,
216 const std::string &fsSource)
217{
Jamie Madillca03b352015-09-02 12:38:13 -0400218 std::vector<std::string> emptyVector;
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800219 return CompileProgramWithGSAndTransformFeedback(vsSource, gsSource, fsSource, emptyVector,
220 GL_NONE);
Jamie Madillca03b352015-09-02 12:38:13 -0400221}
222
Geoff Lang712e3f42014-03-03 11:14:15 -0500223GLuint CompileProgramFromFiles(const std::string &vsPath, const std::string &fsPath)
224{
225 std::string vsSource = ReadFileToString(vsPath);
226 std::string fsSource = ReadFileToString(fsPath);
227 if (vsSource.empty() || fsSource.empty())
228 {
229 return 0;
230 }
231
232 return CompileProgram(vsSource, fsSource);
233}
Martin Radev4c4c8e72016-08-04 12:25:34 +0300234
235GLuint CompileComputeProgram(const std::string &csSource, bool outputErrorMessages)
236{
237 GLuint program = glCreateProgram();
238
239 GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
240 if (cs == 0)
241 {
242 glDeleteProgram(program);
243 return 0;
244 }
245
246 glAttachShader(program, cs);
247
248 glLinkProgram(program);
249
250 return CheckLinkStatusAndReturnProgram(program, outputErrorMessages);
251}
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500252
253GLuint LoadBinaryProgramOES(const std::vector<uint8_t> &binary, GLenum binaryFormat)
254{
255 GLuint program = glCreateProgram();
256 glProgramBinaryOES(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
257 return CheckLinkStatusAndReturnProgram(program, true);
258}
259
260GLuint LoadBinaryProgramES3(const std::vector<uint8_t> &binary, GLenum binaryFormat)
261{
262 GLuint program = glCreateProgram();
263 glProgramBinary(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
264 return CheckLinkStatusAndReturnProgram(program, true);
265}
Jamie Madill401345e2017-08-21 10:52:40 -0400266
267bool LinkAttachedProgram(GLuint program)
268{
269 glLinkProgram(program);
270 return (CheckLinkStatusAndReturnProgram(program, true) != 0);
271}
Olli Etuaho5804dc82018-04-13 14:11:46 +0300272
273namespace angle
274{
275
276namespace essl1_shaders
277{
278
279const char *PositionAttrib()
280{
281 return "a_position";
282}
283const char *ColorUniform()
284{
285 return "u_color";
286}
287
288namespace vs
289{
290
291// A shader that sets gl_Position to zero.
292const char *Zero()
293{
294 return R"(void main()
295{
296 gl_Position = vec4(0);
297})";
298}
299
300// A shader that sets gl_Position to attribute a_position.
301const char *Simple()
302{
303 return R"(precision highp float;
304attribute vec4 a_position;
305
306void main()
307{
308 gl_Position = a_position;
309})";
310}
311
312// A shader that simply passes through attribute a_position, setting it to gl_Position and varying
Olli Etuahodff32a02018-08-28 14:35:50 +0300313// v_position.
Olli Etuaho5804dc82018-04-13 14:11:46 +0300314const char *Passthrough()
315{
316 return R"(precision highp float;
317attribute vec4 a_position;
318varying vec4 v_position;
319
320void main()
321{
322 gl_Position = a_position;
323 v_position = a_position;
324})";
325}
326
327} // namespace vs
328
329namespace fs
330{
331
332// A shader that renders a simple checker pattern of red and green. X axis and y axis separate the
333// different colors. Needs varying v_position.
334const char *Checkered()
335{
336 return R"(precision highp float;
337varying vec4 v_position;
338
339void main()
340{
341 if (v_position.x * v_position.y > 0.0)
342 {
343 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
344 }
345 else
346 {
347 gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
348 }
349})";
350}
351
352// A shader that fills with color taken from uniform named "color".
353const char *UniformColor()
354{
355 return R"(uniform mediump vec4 u_color;
356void main(void)
357{
358 gl_FragColor = u_color;
359})";
360}
361
362// A shader that fills with 100% opaque red.
363const char *Red()
364{
365 return R"(precision mediump float;
366
367void main()
368{
369 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
370})";
371}
372
373// A shader that fills with 100% opaque blue.
374const char *Blue()
375{
376 return R"(precision mediump float;
377
378void main()
379{
380 gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
381})";
382}
383
384} // namespace fs
385} // namespace essl1_shaders
386
387namespace essl3_shaders
388{
389
390const char *PositionAttrib()
391{
392 return "a_position";
393}
394
395namespace vs
396{
397
398// A shader that sets gl_Position to zero.
399const char *Zero()
400{
401 return R"(#version 300 es
402void main()
403{
404 gl_Position = vec4(0);
405})";
406}
407
408// A shader that sets gl_Position to attribute a_position.
409const char *Simple()
410{
411 return R"(#version 300 es
412in vec4 a_position;
413void main()
414{
415 gl_Position = a_position;
416})";
417}
418
419} // namespace vs
420
421namespace fs
422{
423
424// A shader that fills with 100% opaque red.
425const char *Red()
426{
427 return R"(#version 300 es
428precision highp float;
429out vec4 my_FragColor;
430void main()
431{
432 my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
433})";
434}
435
436} // namespace fs
437} // namespace essl3_shaders
438
439namespace essl31_shaders
440{
441
442const char *PositionAttrib()
443{
444 return "a_position";
445}
446
447namespace vs
448{
449
450// A shader that sets gl_Position to zero.
451const char *Zero()
452{
453 return R"(#version 310 es
454void main()
455{
456 gl_Position = vec4(0);
457})";
458}
459
460// A shader that sets gl_Position to attribute a_position.
461const char *Simple()
462{
463 return R"(#version 310 es
464in vec4 a_position;
465void main()
466{
467 gl_Position = a_position;
468})";
469}
470
Olli Etuahodff32a02018-08-28 14:35:50 +0300471// A shader that simply passes through attribute a_position, setting it to gl_Position and varying
472// v_position.
473const char *Passthrough()
474{
475 return R"(#version 310 es
476in vec4 a_position;
477out vec4 v_position;
478void main()
479{
480 gl_Position = a_position;
481 v_position = a_position;
482})";
483}
484
Olli Etuaho5804dc82018-04-13 14:11:46 +0300485} // namespace vs
486
487namespace fs
488{
489
490// A shader that fills with 100% opaque red.
491const char *Red()
492{
493 return R"(#version 310 es
494precision highp float;
495out vec4 my_FragColor;
496void main()
497{
498 my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
499})";
500}
501
502} // namespace fs
503} // namespace essl31_shaders
504} // namespace angle