704964be33
PiperOrigin-RevId: 500802177
208 lines
6.4 KiB
C++
208 lines
6.4 KiB
C++
// Copyright 2019 The MediaPipe Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "mediapipe/gpu/shader_util.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "mediapipe/framework/port/logging.h"
|
|
|
|
#if DEBUG
|
|
#define GL_DEBUG_LOG(type, object, action) \
|
|
do { \
|
|
GLint log_length = 0; \
|
|
glGet##type##iv(object, GL_INFO_LOG_LENGTH, &log_length); \
|
|
if (log_length > 0) { \
|
|
GLchar* log = static_cast<GLchar*>(malloc(log_length)); \
|
|
glGet##type##InfoLog(object, log_length, &log_length, log); \
|
|
LOG(INFO) << #type " " action " log:\n" << log; \
|
|
free(log); \
|
|
} \
|
|
} while (0)
|
|
#else
|
|
#define GL_DEBUG_LOG(type, object, action)
|
|
#endif
|
|
|
|
#define GL_ERROR_LOG(type, object, action) \
|
|
do { \
|
|
GLint log_length = 0; \
|
|
glGet##type##iv(object, GL_INFO_LOG_LENGTH, &log_length); \
|
|
if (log_length > 0) { \
|
|
GLchar* log = static_cast<GLchar*>(malloc(log_length)); \
|
|
glGet##type##InfoLog(object, log_length, &log_length, log); \
|
|
LOG(ERROR) << #type " " action " log:\n" << log; \
|
|
free(log); \
|
|
} \
|
|
} while (0)
|
|
|
|
namespace mediapipe {
|
|
|
|
constexpr int kMaxShaderInfoLength = 1024;
|
|
|
|
GLint GlhCompileShader(GLenum target, const GLchar* source, GLuint* shader,
|
|
bool force_log_errors) {
|
|
*shader = glCreateShader(target);
|
|
if (*shader == 0) {
|
|
return GL_FALSE;
|
|
}
|
|
glShaderSource(*shader, 1, &source, NULL);
|
|
glCompileShader(*shader);
|
|
|
|
GL_DEBUG_LOG(Shader, *shader, "compile");
|
|
|
|
#if UNSAFE_EMSCRIPTEN_SKIP_GL_ERROR_HANDLING
|
|
if (!force_log_errors) {
|
|
return GL_TRUE;
|
|
}
|
|
#endif // UNSAFE_EMSCRIPTEN_SKIP_GL_ERROR_HANDLING
|
|
|
|
GLint status;
|
|
|
|
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
|
|
LOG_IF(ERROR, status == GL_FALSE) << "Failed to compile shader:\n" << source;
|
|
|
|
if (status == GL_FALSE) {
|
|
int length = 0;
|
|
GLchar cmessage[kMaxShaderInfoLength];
|
|
glGetShaderInfoLog(*shader, kMaxShaderInfoLength, &length, cmessage);
|
|
LOG(ERROR) << "Error message: " << std::string(cmessage, length);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
GLint GlhLinkProgram(GLuint program, bool force_log_errors) {
|
|
glLinkProgram(program);
|
|
|
|
#if UNSAFE_EMSCRIPTEN_SKIP_GL_ERROR_HANDLING
|
|
if (!force_log_errors) {
|
|
return GL_TRUE;
|
|
}
|
|
#endif // UNSAFE_EMSCRIPTEN_SKIP_GL_ERROR_HANDLING
|
|
|
|
GLint status;
|
|
|
|
GL_DEBUG_LOG(Program, program, "link");
|
|
|
|
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
|
LOG_IF(ERROR, status == GL_FALSE) << "Failed to link program " << program;
|
|
|
|
return status;
|
|
}
|
|
|
|
GLint GlhValidateProgram(GLuint program) {
|
|
GLint status;
|
|
|
|
glValidateProgram(program);
|
|
|
|
GL_DEBUG_LOG(Program, program, "validate");
|
|
|
|
glGetProgramiv(program, GL_VALIDATE_STATUS, &status);
|
|
LOG_IF(ERROR, status == GL_FALSE) << "Failed to validate program " << program;
|
|
|
|
return status;
|
|
}
|
|
|
|
GLint GlhCreateProgram(const GLchar* vert_src, const GLchar* frag_src,
|
|
GLsizei attr_count, const GLchar* const* attr_names,
|
|
const GLint* attr_locations, GLuint* program,
|
|
bool force_log_errors) {
|
|
GLuint vert_shader = 0;
|
|
GLuint frag_shader = 0;
|
|
GLint ok = GL_TRUE;
|
|
|
|
*program = glCreateProgram();
|
|
if (*program == 0) {
|
|
return GL_FALSE;
|
|
}
|
|
|
|
ok = ok && GlhCompileShader(GL_VERTEX_SHADER, vert_src, &vert_shader,
|
|
force_log_errors);
|
|
ok = ok && GlhCompileShader(GL_FRAGMENT_SHADER, frag_src, &frag_shader,
|
|
force_log_errors);
|
|
|
|
if (ok) {
|
|
glAttachShader(*program, vert_shader);
|
|
glAttachShader(*program, frag_shader);
|
|
|
|
// Attribute location binding must be set before linking.
|
|
for (int i = 0; i < attr_count; i++) {
|
|
glBindAttribLocation(*program, attr_locations[i], attr_names[i]);
|
|
}
|
|
|
|
ok = GlhLinkProgram(*program, force_log_errors);
|
|
}
|
|
|
|
if (vert_shader) glDeleteShader(vert_shader);
|
|
if (frag_shader) glDeleteShader(frag_shader);
|
|
|
|
if (!ok) {
|
|
glDeleteProgram(*program);
|
|
*program = 0;
|
|
}
|
|
|
|
return ok;
|
|
}
|
|
|
|
bool CompileShader(GLenum shader_type, const std::string& shader_source,
|
|
GLuint* shader) {
|
|
*shader = glCreateShader(shader_type);
|
|
if (*shader == 0) {
|
|
VLOG(2) << "Unable to create shader of type: " << shader_type;
|
|
return false;
|
|
}
|
|
const char* shader_source_cstr = shader_source.c_str();
|
|
glShaderSource(*shader, 1, &shader_source_cstr, NULL);
|
|
glCompileShader(*shader);
|
|
|
|
GLint compiled;
|
|
glGetShaderiv(*shader, GL_COMPILE_STATUS, &compiled);
|
|
if (!compiled) {
|
|
VLOG(2) << "Unable to compile shader:\n" << shader_source;
|
|
GL_ERROR_LOG(Shader, *shader, "compile");
|
|
glDeleteShader(*shader);
|
|
*shader = 0;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CreateShaderProgram(
|
|
GLuint vertex_shader, GLuint fragment_shader,
|
|
const std::unordered_map<GLuint, std::string>& attributes,
|
|
GLuint* shader_program) {
|
|
*shader_program = glCreateProgram();
|
|
if (*shader_program == 0) {
|
|
VLOG(2) << "Unable to create shader program";
|
|
return false;
|
|
}
|
|
glAttachShader(*shader_program, vertex_shader);
|
|
glAttachShader(*shader_program, fragment_shader);
|
|
|
|
for (const auto& it : attributes) {
|
|
glBindAttribLocation(*shader_program, it.first, it.second.c_str());
|
|
}
|
|
glLinkProgram(*shader_program);
|
|
|
|
GLint is_linked = 0;
|
|
glGetProgramiv(*shader_program, GL_LINK_STATUS, &is_linked);
|
|
if (!is_linked) {
|
|
glDeleteProgram(*shader_program);
|
|
*shader_program = 0;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
} // namespace mediapipe
|