blob: 3b6dffaf9899efdab879a069f07f29ec1efd3705 [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{
125 GLuint program = glCreateProgram();
126
127 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
128 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
129
130 if (vs == 0 || fs == 0)
131 {
132 glDeleteShader(fs);
133 glDeleteShader(vs);
134 glDeleteProgram(program);
135 return 0;
136 }
137
138 glAttachShader(program, vs);
139 glDeleteShader(vs);
140
141 glAttachShader(program, fs);
142 glDeleteShader(fs);
143
Jamie Madillca03b352015-09-02 12:38:13 -0400144 if (transformFeedbackVaryings.size() > 0)
145 {
146 std::vector<const char *> constCharTFVaryings;
147
148 for (const std::string &transformFeedbackVarying : transformFeedbackVaryings)
149 {
150 constCharTFVaryings.push_back(transformFeedbackVarying.c_str());
151 }
152
153 glTransformFeedbackVaryings(program, static_cast<GLsizei>(transformFeedbackVaryings.size()),
154 &constCharTFVaryings[0], bufferMode);
155 }
156
Geoff Lang49be2ad2014-02-28 13:05:51 -0500157 glLinkProgram(program);
158
Martin Radev4c4c8e72016-08-04 12:25:34 +0300159 return CheckLinkStatusAndReturnProgram(program, true);
Geoff Lang49be2ad2014-02-28 13:05:51 -0500160}
Geoff Lang712e3f42014-03-03 11:14:15 -0500161
Jamie Madillca03b352015-09-02 12:38:13 -0400162GLuint CompileProgram(const std::string &vsSource, const std::string &fsSource)
163{
164 std::vector<std::string> emptyVector;
165 return CompileProgramWithTransformFeedback(vsSource, fsSource, emptyVector, GL_NONE);
166}
167
Geoff Lang712e3f42014-03-03 11:14:15 -0500168GLuint CompileProgramFromFiles(const std::string &vsPath, const std::string &fsPath)
169{
170 std::string vsSource = ReadFileToString(vsPath);
171 std::string fsSource = ReadFileToString(fsPath);
172 if (vsSource.empty() || fsSource.empty())
173 {
174 return 0;
175 }
176
177 return CompileProgram(vsSource, fsSource);
178}
Martin Radev4c4c8e72016-08-04 12:25:34 +0300179
180GLuint CompileComputeProgram(const std::string &csSource, bool outputErrorMessages)
181{
182 GLuint program = glCreateProgram();
183
184 GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
185 if (cs == 0)
186 {
187 glDeleteProgram(program);
188 return 0;
189 }
190
191 glAttachShader(program, cs);
192
193 glLinkProgram(program);
194
195 return CheckLinkStatusAndReturnProgram(program, outputErrorMessages);
196}
Jamie Madilla7d12dc2016-12-13 15:08:19 -0500197
198GLuint LoadBinaryProgramOES(const std::vector<uint8_t> &binary, GLenum binaryFormat)
199{
200 GLuint program = glCreateProgram();
201 glProgramBinaryOES(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
202 return CheckLinkStatusAndReturnProgram(program, true);
203}
204
205GLuint LoadBinaryProgramES3(const std::vector<uint8_t> &binary, GLenum binaryFormat)
206{
207 GLuint program = glCreateProgram();
208 glProgramBinary(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
209 return CheckLinkStatusAndReturnProgram(program, true);
210}
Jamie Madill401345e2017-08-21 10:52:40 -0400211
212bool LinkAttachedProgram(GLuint program)
213{
214 glLinkProgram(program);
215 return (CheckLinkStatusAndReturnProgram(program, true) != 0);
216}