2014-02-28 22:05:51 +04:00
|
|
|
//
|
|
|
|
// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "shader_utils.h"
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <iostream>
|
2014-03-03 20:14:15 +04:00
|
|
|
#include <fstream>
|
|
|
|
|
|
|
|
static std::string ReadFileToString(const std::string &source)
|
|
|
|
{
|
2015-09-14 21:53:10 +03:00
|
|
|
std::ifstream stream(source.c_str());
|
2014-03-03 20:14:15 +04:00
|
|
|
if (!stream)
|
|
|
|
{
|
|
|
|
std::cerr << "Failed to load shader file: " << source;
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string result;
|
|
|
|
|
|
|
|
stream.seekg(0, std::ios::end);
|
2015-04-08 04:31:54 +03:00
|
|
|
result.reserve(static_cast<unsigned int>(stream.tellg()));
|
2014-03-03 20:14:15 +04:00
|
|
|
stream.seekg(0, std::ios::beg);
|
|
|
|
|
|
|
|
result.assign((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2014-02-28 22:05:51 +04:00
|
|
|
|
|
|
|
GLuint CompileShader(GLenum type, const std::string &source)
|
|
|
|
{
|
|
|
|
GLuint shader = glCreateShader(type);
|
|
|
|
|
|
|
|
const char *sourceArray[1] = { source.c_str() };
|
2017-04-24 05:49:17 +03:00
|
|
|
glShaderSource(shader, 1, sourceArray, nullptr);
|
2014-02-28 22:05:51 +04:00
|
|
|
glCompileShader(shader);
|
|
|
|
|
|
|
|
GLint compileResult;
|
|
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
|
|
|
|
|
|
|
|
if (compileResult == 0)
|
|
|
|
{
|
|
|
|
GLint infoLogLength;
|
|
|
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
|
|
|
|
|
2016-03-08 16:43:55 +03:00
|
|
|
// Info log length includes the null terminator, so 1 means that the info log is an empty
|
|
|
|
// string.
|
|
|
|
if (infoLogLength > 1)
|
2015-12-15 23:14:08 +03:00
|
|
|
{
|
|
|
|
std::vector<GLchar> infoLog(infoLogLength);
|
2017-04-24 05:49:17 +03:00
|
|
|
glGetShaderInfoLog(shader, static_cast<GLsizei>(infoLog.size()), nullptr, &infoLog[0]);
|
2015-12-15 23:14:08 +03:00
|
|
|
std::cerr << "shader compilation failed: " << &infoLog[0];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cerr << "shader compilation failed. <Empty log message>";
|
|
|
|
}
|
2014-02-28 22:05:51 +04:00
|
|
|
|
2017-06-05 19:59:21 +03:00
|
|
|
std::cerr << std::endl;
|
|
|
|
|
2014-02-28 22:05:51 +04:00
|
|
|
glDeleteShader(shader);
|
|
|
|
shader = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return shader;
|
|
|
|
}
|
|
|
|
|
2014-03-03 20:14:15 +04:00
|
|
|
GLuint CompileShaderFromFile(GLenum type, const std::string &sourcePath)
|
|
|
|
{
|
|
|
|
std::string source = ReadFileToString(sourcePath);
|
|
|
|
if (source.empty())
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CompileShader(type, source);
|
|
|
|
}
|
|
|
|
|
2016-08-04 12:25:34 +03:00
|
|
|
GLuint CheckLinkStatusAndReturnProgram(GLuint program, bool outputErrorMessages)
|
|
|
|
{
|
2016-12-13 23:08:19 +03:00
|
|
|
if (glGetError() != GL_NO_ERROR)
|
|
|
|
return 0;
|
|
|
|
|
2016-08-04 12:25:34 +03:00
|
|
|
GLint linkStatus;
|
|
|
|
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
|
|
|
|
if (linkStatus == 0)
|
|
|
|
{
|
|
|
|
if (outputErrorMessages)
|
|
|
|
{
|
|
|
|
GLint infoLogLength;
|
|
|
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
|
|
|
|
|
|
|
|
// Info log length includes the null terminator, so 1 means that the info log is an
|
|
|
|
// empty string.
|
|
|
|
if (infoLogLength > 1)
|
|
|
|
{
|
|
|
|
std::vector<GLchar> infoLog(infoLogLength);
|
|
|
|
glGetProgramInfoLog(program, static_cast<GLsizei>(infoLog.size()), nullptr,
|
|
|
|
&infoLog[0]);
|
|
|
|
|
|
|
|
std::cerr << "program link failed: " << &infoLog[0];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cerr << "program link failed. <Empty log message>";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
glDeleteProgram(program);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return program;
|
|
|
|
}
|
|
|
|
|
2015-09-02 19:38:13 +03:00
|
|
|
GLuint CompileProgramWithTransformFeedback(
|
|
|
|
const std::string &vsSource,
|
|
|
|
const std::string &fsSource,
|
|
|
|
const std::vector<std::string> &transformFeedbackVaryings,
|
|
|
|
GLenum bufferMode)
|
2018-02-02 09:26:15 +03:00
|
|
|
{
|
|
|
|
return CompileProgramWithGSAndTransformFeedback(vsSource, "", fsSource,
|
|
|
|
transformFeedbackVaryings, bufferMode);
|
|
|
|
}
|
|
|
|
|
|
|
|
GLuint CompileProgramWithGSAndTransformFeedback(
|
|
|
|
const std::string &vsSource,
|
|
|
|
const std::string &gsSource,
|
|
|
|
const std::string &fsSource,
|
|
|
|
const std::vector<std::string> &transformFeedbackVaryings,
|
|
|
|
GLenum bufferMode)
|
2014-02-28 22:05:51 +04:00
|
|
|
{
|
|
|
|
GLuint program = glCreateProgram();
|
|
|
|
|
|
|
|
GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
|
|
|
|
GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
|
|
|
|
|
|
|
|
if (vs == 0 || fs == 0)
|
|
|
|
{
|
|
|
|
glDeleteShader(fs);
|
|
|
|
glDeleteShader(vs);
|
|
|
|
glDeleteProgram(program);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
glAttachShader(program, vs);
|
|
|
|
glDeleteShader(vs);
|
|
|
|
|
|
|
|
glAttachShader(program, fs);
|
|
|
|
glDeleteShader(fs);
|
|
|
|
|
2018-02-02 09:26:15 +03:00
|
|
|
if (!gsSource.empty())
|
|
|
|
{
|
|
|
|
GLuint gs = CompileShader(GL_GEOMETRY_SHADER_EXT, gsSource);
|
|
|
|
if (gs == 0)
|
|
|
|
{
|
|
|
|
glDeleteShader(vs);
|
|
|
|
glDeleteShader(fs);
|
|
|
|
glDeleteProgram(program);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
glAttachShader(program, gs);
|
|
|
|
glDeleteShader(gs);
|
|
|
|
}
|
|
|
|
|
2015-09-02 19:38:13 +03:00
|
|
|
if (transformFeedbackVaryings.size() > 0)
|
|
|
|
{
|
|
|
|
std::vector<const char *> constCharTFVaryings;
|
|
|
|
|
|
|
|
for (const std::string &transformFeedbackVarying : transformFeedbackVaryings)
|
|
|
|
{
|
|
|
|
constCharTFVaryings.push_back(transformFeedbackVarying.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
glTransformFeedbackVaryings(program, static_cast<GLsizei>(transformFeedbackVaryings.size()),
|
|
|
|
&constCharTFVaryings[0], bufferMode);
|
|
|
|
}
|
|
|
|
|
2014-02-28 22:05:51 +04:00
|
|
|
glLinkProgram(program);
|
|
|
|
|
2016-08-04 12:25:34 +03:00
|
|
|
return CheckLinkStatusAndReturnProgram(program, true);
|
2014-02-28 22:05:51 +04:00
|
|
|
}
|
2014-03-03 20:14:15 +04:00
|
|
|
|
2015-09-02 19:38:13 +03:00
|
|
|
GLuint CompileProgram(const std::string &vsSource, const std::string &fsSource)
|
2018-02-02 09:26:15 +03:00
|
|
|
{
|
|
|
|
return CompileProgramWithGS(vsSource, "", fsSource);
|
|
|
|
}
|
|
|
|
|
|
|
|
GLuint CompileProgramWithGS(const std::string &vsSource,
|
|
|
|
const std::string &gsSource,
|
|
|
|
const std::string &fsSource)
|
2015-09-02 19:38:13 +03:00
|
|
|
{
|
|
|
|
std::vector<std::string> emptyVector;
|
2018-02-02 09:26:15 +03:00
|
|
|
return CompileProgramWithGSAndTransformFeedback(vsSource, gsSource, fsSource, emptyVector,
|
|
|
|
GL_NONE);
|
2015-09-02 19:38:13 +03:00
|
|
|
}
|
|
|
|
|
2014-03-03 20:14:15 +04:00
|
|
|
GLuint CompileProgramFromFiles(const std::string &vsPath, const std::string &fsPath)
|
|
|
|
{
|
|
|
|
std::string vsSource = ReadFileToString(vsPath);
|
|
|
|
std::string fsSource = ReadFileToString(fsPath);
|
|
|
|
if (vsSource.empty() || fsSource.empty())
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CompileProgram(vsSource, fsSource);
|
|
|
|
}
|
2016-08-04 12:25:34 +03:00
|
|
|
|
|
|
|
GLuint CompileComputeProgram(const std::string &csSource, bool outputErrorMessages)
|
|
|
|
{
|
|
|
|
GLuint program = glCreateProgram();
|
|
|
|
|
|
|
|
GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
|
|
|
|
if (cs == 0)
|
|
|
|
{
|
|
|
|
glDeleteProgram(program);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
glAttachShader(program, cs);
|
|
|
|
|
|
|
|
glLinkProgram(program);
|
|
|
|
|
|
|
|
return CheckLinkStatusAndReturnProgram(program, outputErrorMessages);
|
|
|
|
}
|
2016-12-13 23:08:19 +03:00
|
|
|
|
|
|
|
GLuint LoadBinaryProgramOES(const std::vector<uint8_t> &binary, GLenum binaryFormat)
|
|
|
|
{
|
|
|
|
GLuint program = glCreateProgram();
|
|
|
|
glProgramBinaryOES(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
|
|
|
|
return CheckLinkStatusAndReturnProgram(program, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
GLuint LoadBinaryProgramES3(const std::vector<uint8_t> &binary, GLenum binaryFormat)
|
|
|
|
{
|
|
|
|
GLuint program = glCreateProgram();
|
|
|
|
glProgramBinary(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
|
|
|
|
return CheckLinkStatusAndReturnProgram(program, true);
|
|
|
|
}
|
2017-08-21 17:52:40 +03:00
|
|
|
|
|
|
|
bool LinkAttachedProgram(GLuint program)
|
|
|
|
{
|
|
|
|
glLinkProgram(program);
|
|
|
|
return (CheckLinkStatusAndReturnProgram(program, true) != 0);
|
|
|
|
}
|