blob: f92d7157034cee12108e82122cb7a14238e33067 [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() };
38 glShaderSource(shader, 1, sourceArray, NULL);
39 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);
54 glGetShaderInfoLog(shader, static_cast<GLsizei>(infoLog.size()), NULL, &infoLog[0]);
55 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
62 glDeleteShader(shader);
63 shader = 0;
64 }
65
66 return shader;
67}
68
Geoff Lang712e3f42014-03-03 11:14:15 -050069GLuint CompileShaderFromFile(GLenum type, const std::string &sourcePath)
70{
71 std::string source = ReadFileToString(sourcePath);
72 if (source.empty())
73 {
74 return 0;
75 }
76
77 return CompileShader(type, source);
78}
79
Martin Radev4c4c8e72016-08-04 12:25:34 +030080GLuint CheckLinkStatusAndReturnProgram(GLuint program, bool outputErrorMessages)
81{
82 GLint linkStatus;
83 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
84 if (linkStatus == 0)
85 {
86 if (outputErrorMessages)
87 {
88 GLint infoLogLength;
89 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
90
91 // Info log length includes the null terminator, so 1 means that the info log is an
92 // empty string.
93 if (infoLogLength > 1)
94 {
95 std::vector<GLchar> infoLog(infoLogLength);
96 glGetProgramInfoLog(program, static_cast<GLsizei>(infoLog.size()), nullptr,
97 &infoLog[0]);
98
99 std::cerr << "program link failed: " << &infoLog[0];
100 }
101 else
102 {
103 std::cerr << "program link failed. <Empty log message>";
104 }
105 }
106
107 glDeleteProgram(program);
108 return 0;
109 }
110
111 return program;
112}
113
Jamie Madillca03b352015-09-02 12:38:13 -0400114GLuint CompileProgramWithTransformFeedback(
115 const std::string &vsSource,
116 const std::string &fsSource,
117 const std::vector<std::string> &transformFeedbackVaryings,
118 GLenum bufferMode)
Geoff Lang49be2ad2014-02-28 13:05:51 -0500119{
120 GLuint program = glCreateProgram();
121
122 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
123 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
124
125 if (vs == 0 || fs == 0)
126 {
127 glDeleteShader(fs);
128 glDeleteShader(vs);
129 glDeleteProgram(program);
130 return 0;
131 }
132
133 glAttachShader(program, vs);
134 glDeleteShader(vs);
135
136 glAttachShader(program, fs);
137 glDeleteShader(fs);
138
Jamie Madillca03b352015-09-02 12:38:13 -0400139 if (transformFeedbackVaryings.size() > 0)
140 {
141 std::vector<const char *> constCharTFVaryings;
142
143 for (const std::string &transformFeedbackVarying : transformFeedbackVaryings)
144 {
145 constCharTFVaryings.push_back(transformFeedbackVarying.c_str());
146 }
147
148 glTransformFeedbackVaryings(program, static_cast<GLsizei>(transformFeedbackVaryings.size()),
149 &constCharTFVaryings[0], bufferMode);
150 }
151
Geoff Lang49be2ad2014-02-28 13:05:51 -0500152 glLinkProgram(program);
153
Martin Radev4c4c8e72016-08-04 12:25:34 +0300154 return CheckLinkStatusAndReturnProgram(program, true);
Geoff Lang49be2ad2014-02-28 13:05:51 -0500155}
Geoff Lang712e3f42014-03-03 11:14:15 -0500156
Jamie Madillca03b352015-09-02 12:38:13 -0400157GLuint CompileProgram(const std::string &vsSource, const std::string &fsSource)
158{
159 std::vector<std::string> emptyVector;
160 return CompileProgramWithTransformFeedback(vsSource, fsSource, emptyVector, GL_NONE);
161}
162
Geoff Lang712e3f42014-03-03 11:14:15 -0500163GLuint CompileProgramFromFiles(const std::string &vsPath, const std::string &fsPath)
164{
165 std::string vsSource = ReadFileToString(vsPath);
166 std::string fsSource = ReadFileToString(fsPath);
167 if (vsSource.empty() || fsSource.empty())
168 {
169 return 0;
170 }
171
172 return CompileProgram(vsSource, fsSource);
173}
Martin Radev4c4c8e72016-08-04 12:25:34 +0300174
175GLuint CompileComputeProgram(const std::string &csSource, bool outputErrorMessages)
176{
177 GLuint program = glCreateProgram();
178
179 GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
180 if (cs == 0)
181 {
182 glDeleteProgram(program);
183 return 0;
184 }
185
186 glAttachShader(program, cs);
187
188 glLinkProgram(program);
189
190 return CheckLinkStatusAndReturnProgram(program, outputErrorMessages);
191}