ppsspp/gfx_es2/glsl_program.cpp

245 lines
6.8 KiB
C++
Raw Normal View History

2012-03-24 23:39:19 +01:00
#if defined(ANDROID)
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
typedef char GLchar;
#else
#include <GL/glew.h>
#if defined(__APPLE__)
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif
#endif
#include <set>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include "base/logging.h"
#include "file/vfs.h"
#include "gfx_es2/glsl_program.h"
static std::set<GLSLProgram *> active_programs;
bool CompileShader(const char *source, GLuint shader, const char *filename) {
2012-05-08 22:04:24 +02:00
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
2012-03-24 23:39:19 +01:00
#define MAX_INFO_LOG_SIZE 2048
2012-05-08 22:04:24 +02:00
GLchar infoLog[MAX_INFO_LOG_SIZE];
2012-03-24 23:39:19 +01:00
GLsizei len;
2012-05-08 22:04:24 +02:00
glGetShaderInfoLog(shader, MAX_INFO_LOG_SIZE, &len, infoLog);
2012-03-24 23:39:19 +01:00
infoLog[len] = '\0';
2012-05-08 22:04:24 +02:00
ELOG("Error in shader compilation of %s!\n", filename);
ELOG("Info log: %s\n", infoLog);
ELOG("Shader source:\n%s\n", (const char *)source);
2012-03-31 22:07:33 +02:00
#ifdef ANDROID
2012-05-08 22:04:24 +02:00
exit(1);
2012-03-31 22:07:33 +02:00
#endif
2012-05-08 22:04:24 +02:00
return false;
}
return true;
2012-03-24 23:39:19 +01:00
}
GLSLProgram *glsl_create(const char *vshader, const char *fshader) {
GLSLProgram *program = new GLSLProgram();
program->program_ = 0;
program->vsh_ = 0;
program->fsh_ = 0;
program->vshader_source = 0;
program->fshader_source = 0;
2012-05-08 22:04:24 +02:00
strcpy(program->name, vshader + strlen(vshader) - 15);
2012-03-24 23:39:19 +01:00
strcpy(program->vshader_filename, vshader);
strcpy(program->fshader_filename, fshader);
if (glsl_recompile(program)) {
active_programs.insert(program);
}
else
{
FLOG("Failed building GLSL program: %s %s", vshader, fshader);
}
register_gl_resource_holder(program);
return program;
}
GLSLProgram *glsl_create_source(const char *vshader_src, const char *fshader_src) {
GLSLProgram *program = new GLSLProgram();
program->program_ = 0;
program->vsh_ = 0;
program->fsh_ = 0;
program->vshader_source = vshader_src;
program->fshader_source = fshader_src;
strcpy(program->name, "[srcshader]");
strcpy(program->vshader_filename, "");
strcpy(program->fshader_filename, "");
if (glsl_recompile(program)) {
active_programs.insert(program);
}
2012-03-24 23:39:19 +01:00
register_gl_resource_holder(program);
return program;
}
bool glsl_up_to_date(GLSLProgram *program) {
struct stat vs, fs;
stat(program->vshader_filename, &vs);
stat(program->fshader_filename, &fs);
if (vs.st_mtime != program->vshader_mtime ||
2012-07-09 01:11:18 +02:00
fs.st_mtime != program->fshader_mtime) {
2012-05-08 22:04:24 +02:00
return false;
2012-03-24 23:39:19 +01:00
} else {
return true;
}
}
void glsl_refresh() {
ILOG("glsl_refresh()");
for (std::set<GLSLProgram *>::const_iterator iter = active_programs.begin();
2012-05-08 22:04:24 +02:00
iter != active_programs.end(); ++iter) {
if (!glsl_up_to_date(*iter)) {
glsl_recompile(*iter);
}
2012-03-24 23:39:19 +01:00
}
}
bool glsl_recompile(GLSLProgram *program) {
struct stat vs, fs;
2012-03-30 00:45:16 +02:00
if (0 == stat(program->vshader_filename, &vs))
2012-05-08 22:04:24 +02:00
program->vshader_mtime = vs.st_mtime;
else
program->vshader_mtime = 0;
2012-03-30 00:45:16 +02:00
if (0 == stat(program->fshader_filename, &fs))
2012-05-08 22:04:24 +02:00
program->fshader_mtime = fs.st_mtime;
else
program->fshader_mtime = 0;
char *vsh_src = 0, *fsh_src = 0;
if (!program->vshader_source)
{
size_t sz;
vsh_src = (char *)VFSReadFile(program->vshader_filename, &sz);
if (!vsh_src) {
ELOG("File missing: %s", program->vshader_filename);
return false;
}
2012-03-24 23:39:19 +01:00
}
if (!program->fshader_source)
{
size_t sz;
fsh_src = (char *)VFSReadFile(program->fshader_filename, &sz);
if (!fsh_src) {
ELOG("File missing: %s", program->fshader_filename);
delete [] vsh_src;
return false;
}
2012-03-24 23:39:19 +01:00
}
2012-05-08 22:04:24 +02:00
GLuint vsh = glCreateShader(GL_VERTEX_SHADER);
const GLchar *vsh_str = program->vshader_source ? program->vshader_source : (const GLchar *)(vsh_src);
2012-05-08 22:04:24 +02:00
if (!CompileShader(vsh_str, vsh, program->vshader_filename)) {
2012-03-24 23:39:19 +01:00
return false;
}
delete [] vsh_src;
const GLchar *fsh_str = program->fshader_source ? program->fshader_source : (const GLchar *)(fsh_src);
2012-05-08 22:04:24 +02:00
GLuint fsh = glCreateShader(GL_FRAGMENT_SHADER);
2012-03-24 23:39:19 +01:00
if (!CompileShader(fsh_str, fsh, program->fshader_filename)) {
glDeleteShader(vsh);
return false;
}
2012-05-08 22:04:24 +02:00
delete [] fsh_src;
2012-03-24 23:39:19 +01:00
GLuint prog = glCreateProgram();
2012-05-08 22:04:24 +02:00
glAttachShader(prog, vsh);
glAttachShader(prog, fsh);
glLinkProgram(prog);
GLint linkStatus;
glGetProgramiv(prog, GL_LINK_STATUS, &linkStatus);
if (linkStatus != GL_TRUE) {
GLint bufLength = 0;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &bufLength);
if (bufLength) {
char* buf = new char[bufLength];
glGetProgramInfoLog(prog, bufLength, NULL, buf);
FLOG("Could not link program:\n %s", buf);
delete [] buf; // we're dead!
} else {
FLOG("Could not link program.");
2012-05-08 22:04:24 +02:00
}
2012-03-24 23:39:19 +01:00
glDeleteShader(vsh);
glDeleteShader(fsh);
2012-05-08 22:04:24 +02:00
return false;
}
2012-03-24 23:39:19 +01:00
// Destroy the old program, if any.
if (program->program_) {
glDeleteProgram(program->program_);
}
program->program_ = prog;
program->vsh_ = vsh;
program->fsh_ = vsh;
2012-05-08 22:04:24 +02:00
program->sampler0 = glGetUniformLocation(program->program_, "sampler0");
program->sampler1 = glGetUniformLocation(program->program_, "sampler1");
2012-03-24 23:39:19 +01:00
2012-05-08 22:04:24 +02:00
program->a_position = glGetAttribLocation(program->program_, "a_position");
program->a_color = glGetAttribLocation(program->program_, "a_color");
program->a_normal = glGetAttribLocation(program->program_, "a_normal");
program->a_texcoord0 = glGetAttribLocation(program->program_, "a_texcoord0");
program->a_texcoord1 = glGetAttribLocation(program->program_, "a_texcoord1");
2012-03-24 23:39:19 +01:00
2012-05-08 22:04:24 +02:00
program->u_worldviewproj = glGetUniformLocation(program->program_, "u_worldviewproj");
program->u_world = glGetUniformLocation(program->program_, "u_world");
program->u_viewproj = glGetUniformLocation(program->program_, "u_viewproj");
program->u_fog = glGetUniformLocation(program->program_, "u_fog");
program->u_sundir = glGetUniformLocation(program->program_, "u_sundir");
program->u_camerapos = glGetUniformLocation(program->program_, "u_camerapos");
2012-03-24 23:39:19 +01:00
2012-05-08 22:04:24 +02:00
//ILOG("Shader compilation success: %s %s",
2012-03-24 23:39:19 +01:00
// program->vshader_filename,
// program->fshader_filename);
return true;
}
void GLSLProgram::GLLost() {
ILOG("Restoring GLSL program %s/%s", this->vshader_filename, this->fshader_filename);
this->program_ = 0;
this->vsh_ = 0;
this->fsh_ = 0;
glsl_recompile(this);
}
int glsl_attrib_loc(const GLSLProgram *program, const char *name) {
return glGetAttribLocation(program->program_, name);
}
int glsl_uniform_loc(const GLSLProgram *program, const char *name) {
return glGetUniformLocation(program->program_, name);
}
void glsl_destroy(GLSLProgram *program) {
unregister_gl_resource_holder(program);
2012-05-08 22:04:24 +02:00
glDeleteShader(program->vsh_);
glDeleteShader(program->fsh_);
glDeleteProgram(program->program_);
2012-03-24 23:39:19 +01:00
active_programs.erase(program);
delete program;
}
void glsl_bind(const GLSLProgram *program) {
2012-05-08 22:04:24 +02:00
glUseProgram(program->program_);
2012-03-24 23:39:19 +01:00
}
void glsl_unbind() {
2012-05-08 22:04:24 +02:00
glUseProgram(0);
2012-03-24 23:39:19 +01:00
}