angle/util/shader_utils.cpp

251 строка
6.9 KiB
C++
Исходник Обычный вид История

//
// 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>
#include <fstream>
static std::string ReadFileToString(const std::string &source)
{
std::ifstream stream(source.c_str());
if (!stream)
{
std::cerr << "Failed to load shader file: " << source;
return "";
}
std::string result;
stream.seekg(0, std::ios::end);
result.reserve(static_cast<unsigned int>(stream.tellg()));
stream.seekg(0, std::ios::beg);
result.assign((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
return result;
}
GLuint CompileShader(GLenum type, const std::string &source)
{
GLuint shader = glCreateShader(type);
const char *sourceArray[1] = { source.c_str() };
glShaderSource(shader, 1, sourceArray, nullptr);
glCompileShader(shader);
GLint compileResult;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
if (compileResult == 0)
{
GLint infoLogLength;
glGetShaderiv(shader, 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);
glGetShaderInfoLog(shader, static_cast<GLsizei>(infoLog.size()), nullptr, &infoLog[0]);
std::cerr << "shader compilation failed: " << &infoLog[0];
}
else
{
std::cerr << "shader compilation failed. <Empty log message>";
}
std::cerr << std::endl;
glDeleteShader(shader);
shader = 0;
}
return shader;
}
GLuint CompileShaderFromFile(GLenum type, const std::string &sourcePath)
{
std::string source = ReadFileToString(sourcePath);
if (source.empty())
{
return 0;
}
return CompileShader(type, source);
}
GLuint CheckLinkStatusAndReturnProgram(GLuint program, bool outputErrorMessages)
{
if (glGetError() != GL_NO_ERROR)
return 0;
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;
}
GLuint CompileProgramWithTransformFeedback(
const std::string &vsSource,
const std::string &fsSource,
const std::vector<std::string> &transformFeedbackVaryings,
GLenum bufferMode)
{
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)
{
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);
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);
}
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);
}
glLinkProgram(program);
return CheckLinkStatusAndReturnProgram(program, true);
}
GLuint CompileProgram(const std::string &vsSource, const std::string &fsSource)
{
return CompileProgramWithGS(vsSource, "", fsSource);
}
GLuint CompileProgramWithGS(const std::string &vsSource,
const std::string &gsSource,
const std::string &fsSource)
{
std::vector<std::string> emptyVector;
return CompileProgramWithGSAndTransformFeedback(vsSource, gsSource, fsSource, emptyVector,
GL_NONE);
}
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);
}
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);
}
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);
}
bool LinkAttachedProgram(GLuint program)
{
glLinkProgram(program);
return (CheckLinkStatusAndReturnProgram(program, true) != 0);
}