blob: 55baa5b4f10a7be34c58d7784694fa47d81eaeee [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
Olli Etuaho624fbdc2018-10-01 11:54:05 +0300119static GLuint CompileProgramInternal(const std::string &vsSource,
120 const std::string &gsSource,
121 const std::string &fsSource,
122 const std::function<void(GLuint)> &preLinkCallback)
Geoff Lang49be2ad2014-02-28 13:05:51 -0500123{
Geoff Lang49be2ad2014-02-28 13:05:51 -0500124 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
125 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
126
127 if (vs == 0 || fs == 0)
128 {
129 glDeleteShader(fs);
130 glDeleteShader(vs);
Geoff Lang49be2ad2014-02-28 13:05:51 -0500131 return 0;
132 }
133
Olli Etuaho624fbdc2018-10-01 11:54:05 +0300134 GLuint program = glCreateProgram();
135
Geoff Lang49be2ad2014-02-28 13:05:51 -0500136 glAttachShader(program, vs);
137 glDeleteShader(vs);
138
139 glAttachShader(program, fs);
140 glDeleteShader(fs);
141
Olli Etuaho624fbdc2018-10-01 11:54:05 +0300142 GLuint gs = 0;
143
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800144 if (!gsSource.empty())
145 {
Olli Etuaho624fbdc2018-10-01 11:54:05 +0300146 gs = CompileShader(GL_GEOMETRY_SHADER_EXT, gsSource);
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800147 if (gs == 0)
148 {
149 glDeleteShader(vs);
150 glDeleteShader(fs);
151 glDeleteProgram(program);
152 return 0;
153 }
154
155 glAttachShader(program, gs);
156 glDeleteShader(gs);
157 }
158
Olli Etuaho624fbdc2018-10-01 11:54:05 +0300159 if (preLinkCallback)
Jamie Madillca03b352015-09-02 12:38:13 -0400160 {
Olli Etuaho624fbdc2018-10-01 11:54:05 +0300161 preLinkCallback(program);
Jamie Madillca03b352015-09-02 12:38:13 -0400162 }
163
Geoff Lang49be2ad2014-02-28 13:05:51 -0500164 glLinkProgram(program);
165
Olli Etuaho624fbdc2018-10-01 11:54:05 +0300166 return CheckLinkStatusAndReturnProgram(program, true);
jchen107ae70d82018-07-06 13:47:01 +0800167}
168
Olli Etuaho624fbdc2018-10-01 11:54:05 +0300169GLuint CompileProgramWithTransformFeedback(
jchen107ae70d82018-07-06 13:47:01 +0800170 const std::string &vsSource,
jchen107ae70d82018-07-06 13:47:01 +0800171 const std::string &fsSource,
172 const std::vector<std::string> &transformFeedbackVaryings,
173 GLenum bufferMode)
174{
Olli Etuaho624fbdc2018-10-01 11:54:05 +0300175 auto preLink = [&](GLuint program) {
176 if (transformFeedbackVaryings.size() > 0)
177 {
178 std::vector<const char *> constCharTFVaryings;
179
180 for (const std::string &transformFeedbackVarying : transformFeedbackVaryings)
181 {
182 constCharTFVaryings.push_back(transformFeedbackVarying.c_str());
183 }
184
185 glTransformFeedbackVaryings(program,
186 static_cast<GLsizei>(transformFeedbackVaryings.size()),
187 &constCharTFVaryings[0], bufferMode);
188 }
189 };
190
191 return CompileProgramInternal(vsSource, "", fsSource, preLink);
Geoff Lang49be2ad2014-02-28 13:05:51 -0500192}
Geoff Lang712e3f42014-03-03 11:14:15 -0500193
Jamie Madillca03b352015-09-02 12:38:13 -0400194GLuint CompileProgram(const std::string &vsSource, const std::string &fsSource)
195{
Olli Etuaho624fbdc2018-10-01 11:54:05 +0300196 return CompileProgramInternal(vsSource, "", fsSource, nullptr);
197}
198
199GLuint CompileProgram(const std::string &vsSource,
200 const std::string &fsSource,
201 const std::function<void(GLuint)> &preLinkCallback)
202{
203 return CompileProgramInternal(vsSource, "", fsSource, preLinkCallback);
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800204}
205
206GLuint CompileProgramWithGS(const std::string &vsSource,
207 const std::string &gsSource,
208 const std::string &fsSource)
209{
Olli Etuaho624fbdc2018-10-01 11:54:05 +0300210 return CompileProgramInternal(vsSource, gsSource, fsSource, nullptr);
Jamie Madillca03b352015-09-02 12:38:13 -0400211}
212
Geoff Lang712e3f42014-03-03 11:14:15 -0500213GLuint CompileProgramFromFiles(const std::string &vsPath, const std::string &fsPath)
214{
215 std::string vsSource = ReadFileToString(vsPath);
216 std::string fsSource = ReadFileToString(fsPath);
217 if (vsSource.empty() || fsSource.empty())
218 {
219 return 0;
220 }
221
222 return CompileProgram(vsSource, fsSource);
223}
Martin Radev4c4c8e72016-08-04 12:25:34 +0300224
225GLuint CompileComputeProgram(const std::string &csSource, bool outputErrorMessages)
226{
227 GLuint program = glCreateProgram();
228
229 GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
230 if (cs == 0)
231 {
232 glDeleteProgram(program);
233 return 0;
234 }
235
236 glAttachShader(program, cs);
237
238 glLinkProgram(program);
239
240 return CheckLinkStatusAndReturnProgram(program, outputErrorMessages);
241}
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500242
243GLuint LoadBinaryProgramOES(const std::vector<uint8_t> &binary, GLenum binaryFormat)
244{
245 GLuint program = glCreateProgram();
246 glProgramBinaryOES(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
247 return CheckLinkStatusAndReturnProgram(program, true);
248}
249
250GLuint LoadBinaryProgramES3(const std::vector<uint8_t> &binary, GLenum binaryFormat)
251{
252 GLuint program = glCreateProgram();
253 glProgramBinary(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
254 return CheckLinkStatusAndReturnProgram(program, true);
255}
Jamie Madill401345e2017-08-21 10:52:40 -0400256
257bool LinkAttachedProgram(GLuint program)
258{
259 glLinkProgram(program);
260 return (CheckLinkStatusAndReturnProgram(program, true) != 0);
261}
Olli Etuaho5804dc82018-04-13 14:11:46 +0300262
263namespace angle
264{
265
266namespace essl1_shaders
267{
268
269const char *PositionAttrib()
270{
271 return "a_position";
272}
273const char *ColorUniform()
274{
275 return "u_color";
276}
277
278namespace vs
279{
280
281// A shader that sets gl_Position to zero.
282const char *Zero()
283{
284 return R"(void main()
285{
286 gl_Position = vec4(0);
287})";
288}
289
290// A shader that sets gl_Position to attribute a_position.
291const char *Simple()
292{
293 return R"(precision highp float;
294attribute vec4 a_position;
295
296void main()
297{
298 gl_Position = a_position;
299})";
300}
301
302// A shader that simply passes through attribute a_position, setting it to gl_Position and varying
Olli Etuahodff32a02018-08-28 14:35:50 +0300303// v_position.
Olli Etuaho5804dc82018-04-13 14:11:46 +0300304const char *Passthrough()
305{
306 return R"(precision highp float;
307attribute vec4 a_position;
308varying vec4 v_position;
309
310void main()
311{
312 gl_Position = a_position;
313 v_position = a_position;
314})";
315}
316
317} // namespace vs
318
319namespace fs
320{
321
322// A shader that renders a simple checker pattern of red and green. X axis and y axis separate the
323// different colors. Needs varying v_position.
324const char *Checkered()
325{
326 return R"(precision highp float;
327varying vec4 v_position;
328
329void main()
330{
331 if (v_position.x * v_position.y > 0.0)
332 {
333 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
334 }
335 else
336 {
337 gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
338 }
339})";
340}
341
342// A shader that fills with color taken from uniform named "color".
343const char *UniformColor()
344{
345 return R"(uniform mediump vec4 u_color;
346void main(void)
347{
348 gl_FragColor = u_color;
349})";
350}
351
352// A shader that fills with 100% opaque red.
353const char *Red()
354{
355 return R"(precision mediump float;
356
357void main()
358{
359 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
360})";
361}
362
Jamie Madillb36a4812018-09-25 10:15:11 -0400363// A shader that fills with 100% opaque green.
364const char *Green()
365{
366 return R"(precision mediump float;
367
368void main()
369{
370 gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
371})";
372}
373
Olli Etuaho5804dc82018-04-13 14:11:46 +0300374// A shader that fills with 100% opaque blue.
375const char *Blue()
376{
377 return R"(precision mediump float;
378
379void main()
380{
381 gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
382})";
383}
384
385} // namespace fs
386} // namespace essl1_shaders
387
388namespace essl3_shaders
389{
390
391const char *PositionAttrib()
392{
393 return "a_position";
394}
395
396namespace vs
397{
398
399// A shader that sets gl_Position to zero.
400const char *Zero()
401{
402 return R"(#version 300 es
403void main()
404{
405 gl_Position = vec4(0);
406})";
407}
408
409// A shader that sets gl_Position to attribute a_position.
410const char *Simple()
411{
412 return R"(#version 300 es
413in vec4 a_position;
414void main()
415{
416 gl_Position = a_position;
417})";
418}
419
420} // namespace vs
421
422namespace fs
423{
424
425// A shader that fills with 100% opaque red.
426const char *Red()
427{
428 return R"(#version 300 es
429precision highp float;
430out vec4 my_FragColor;
431void main()
432{
433 my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
434})";
435}
436
437} // namespace fs
438} // namespace essl3_shaders
439
440namespace essl31_shaders
441{
442
443const char *PositionAttrib()
444{
445 return "a_position";
446}
447
448namespace vs
449{
450
451// A shader that sets gl_Position to zero.
452const char *Zero()
453{
454 return R"(#version 310 es
455void main()
456{
457 gl_Position = vec4(0);
458})";
459}
460
461// A shader that sets gl_Position to attribute a_position.
462const char *Simple()
463{
464 return R"(#version 310 es
465in vec4 a_position;
466void main()
467{
468 gl_Position = a_position;
469})";
470}
471
Olli Etuahodff32a02018-08-28 14:35:50 +0300472// A shader that simply passes through attribute a_position, setting it to gl_Position and varying
473// v_position.
474const char *Passthrough()
475{
476 return R"(#version 310 es
477in vec4 a_position;
478out vec4 v_position;
479void main()
480{
481 gl_Position = a_position;
482 v_position = a_position;
483})";
484}
485
Olli Etuaho5804dc82018-04-13 14:11:46 +0300486} // namespace vs
487
488namespace fs
489{
490
491// A shader that fills with 100% opaque red.
492const char *Red()
493{
494 return R"(#version 310 es
495precision highp float;
496out vec4 my_FragColor;
497void main()
498{
499 my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
500})";
501}
502
503} // namespace fs
504} // namespace essl31_shaders
505} // namespace angle