/*
* Copyright © 2015 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authored by: Daniel van Vugt
*/
#include "anbox/graphics/program_family.h"
#include "anbox/graphics/emugl/DispatchTables.h"
#include
#include
namespace anbox {
namespace graphics {
void ProgramFamily::Shader::init(GLenum type, const GLchar* src) {
if (!id) {
id = s_gles2.glCreateShader(type);
if (id) {
s_gles2.glShaderSource(id, 1, &src, NULL);
s_gles2.glCompileShader(id);
GLint ok;
s_gles2.glGetShaderiv(id, GL_COMPILE_STATUS, &ok);
if (!ok) {
GLchar log[1024];
s_gles2.glGetShaderInfoLog(id, sizeof log - 1, NULL, log);
log[sizeof log - 1] = '\0';
s_gles2.glDeleteShader(id);
id = 0;
throw std::runtime_error(std::string("Compile failed: ") + log +
" for:\n" + src);
}
}
}
}
ProgramFamily::~ProgramFamily() noexcept {
// shader and program lifetimes are managed manually, so that we don't
// need any reference counting or to worry about how many copy constructions
// might have been followed by destructor calls during container resizes.
for (auto& p : program) {
if (p.second.id) s_gles2.glDeleteProgram(p.second.id);
}
for (auto& v : vshader) {
if (v.second.id) s_gles2.glDeleteShader(v.second.id);
}
for (auto& f : fshader) {
if (f.second.id) s_gles2.glDeleteShader(f.second.id);
}
}
GLuint ProgramFamily::add_program(const GLchar* const vshader_src,
const GLchar* const fshader_src) {
auto& v = vshader[vshader_src];
if (!v.id) v.init(GL_VERTEX_SHADER, vshader_src);
auto& f = fshader[fshader_src];
if (!f.id) f.init(GL_FRAGMENT_SHADER, fshader_src);
auto& p = program[{v.id, f.id}];
if (!p.id) {
p.id = s_gles2.glCreateProgram();
s_gles2.glAttachShader(p.id, v.id);
s_gles2.glAttachShader(p.id, f.id);
s_gles2.glLinkProgram(p.id);
GLint ok;
s_gles2.glGetProgramiv(p.id, GL_LINK_STATUS, &ok);
if (!ok) {
GLchar log[1024];
s_gles2.glGetProgramInfoLog(p.id, sizeof log - 1, NULL, log);
log[sizeof log - 1] = '\0';
s_gles2.glDeleteShader(p.id);
p.id = 0;
throw std::runtime_error(std::string("Link failed: ") + log);
}
}
return p.id;
}
} // namespace graphics
} // namespace anbox