Do not crash on broken shaders, allow error message return

This commit is contained in:
Henrik Rydgard 2013-10-13 11:56:42 +02:00
parent a25169dc4c
commit d19cef2395
3 changed files with 42 additions and 31 deletions

View File

@ -7,6 +7,10 @@
// Disable annoying warnings in VS
#ifdef _MSC_VER
#pragma warning (disable:4996) //strcpy may be dangerous
#if !defined(snprintf)
#define snprintf _snprintf
#endif
#endif
#undef Crash
@ -66,10 +70,10 @@ inline void Crash() {
void OutputDebugStringUTF8(const char *p);
#define ILOG(...) {char temp[512]; char *p = temp; p += sprintf(p, "I: %s:%i: ", __FILE__, __LINE__); p += sprintf(p, "I: " __VA_ARGS__); p += sprintf(p, "\n"); OutputDebugStringUTF8(temp);}
#define WLOG(...) {char temp[512]; char *p = temp; p += sprintf(p, "W: %s:%i: ", __FILE__, __LINE__); p += sprintf(p, "W: " __VA_ARGS__); p += sprintf(p, "\n"); OutputDebugStringUTF8(temp);}
#define ELOG(...) {char temp[512]; char *p = temp; p += sprintf(p, "E: %s:%i: ", __FILE__, __LINE__); p += sprintf(p, "E: " __VA_ARGS__); p += sprintf(p, "\n"); OutputDebugStringUTF8(temp);}
#define FLOG(...) {char temp[512]; char *p = temp; p += sprintf(p, "F: %s:%i: ", __FILE__, __LINE__); p += sprintf(p, "F: " __VA_ARGS__); p += sprintf(p, "\n"); OutputDebugStringUTF8(temp); Crash();}
#define ILOG(...) {char temp[512]; char *p = temp; p += sprintf(p, "I: %s:%i: ", __FILE__, __LINE__); p += snprintf(p, 450, "I: " __VA_ARGS__); p += sprintf(p, "\n"); OutputDebugStringUTF8(temp);}
#define WLOG(...) {char temp[512]; char *p = temp; p += sprintf(p, "W: %s:%i: ", __FILE__, __LINE__); p += snprintf(p, 450, "W: " __VA_ARGS__); p += sprintf(p, "\n"); OutputDebugStringUTF8(temp);}
#define ELOG(...) {char temp[512]; char *p = temp; p += sprintf(p, "E: %s:%i: ", __FILE__, __LINE__); p += snprintf(p, 450, "E: " __VA_ARGS__); p += sprintf(p, "\n"); OutputDebugStringUTF8(temp);}
#define FLOG(...) {char temp[512]; char *p = temp; p += sprintf(p, "F: %s:%i: ", __FILE__, __LINE__); p += snprintf(p, 450, "F: " __VA_ARGS__); p += sprintf(p, "\n"); OutputDebugStringUTF8(temp); Crash();}
// TODO: Win32 version using OutputDebugString
#else

View File

@ -10,7 +10,7 @@
static std::set<GLSLProgram *> active_programs;
bool CompileShader(const char *source, GLuint shader, const char *filename) {
bool CompileShader(const char *source, GLuint shader, const char *filename, std::string *error_message) {
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
GLint success;
@ -24,12 +24,14 @@ bool CompileShader(const char *source, GLuint shader, const char *filename) {
ELOG("Error in shader compilation of %s!\n", filename);
ELOG("Info log: %s\n", infoLog);
ELOG("Shader source:\n%s\n", (const char *)source);
if (error_message)
*error_message = infoLog;
return false;
}
return true;
}
GLSLProgram *glsl_create(const char *vshader, const char *fshader) {
GLSLProgram *glsl_create(const char *vshader, const char *fshader, std::string *error_message) {
GLSLProgram *program = new GLSLProgram();
program->program_ = 0;
program->vsh_ = 0;
@ -39,18 +41,18 @@ GLSLProgram *glsl_create(const char *vshader, const char *fshader) {
strcpy(program->name, vshader + strlen(vshader) - 15);
strcpy(program->vshader_filename, vshader);
strcpy(program->fshader_filename, fshader);
if (glsl_recompile(program)) {
if (glsl_recompile(program, error_message)) {
active_programs.insert(program);
}
else
{
FLOG("Failed building GLSL program: %s %s", vshader, fshader);
} else {
ELOG("Failed compiling GLSL program: %s %s", vshader, fshader);
delete program;
return 0;
}
register_gl_resource_holder(program);
return program;
}
GLSLProgram *glsl_create_source(const char *vshader_src, const char *fshader_src) {
GLSLProgram *glsl_create_source(const char *vshader_src, const char *fshader_src, std::string *error_message) {
GLSLProgram *program = new GLSLProgram();
program->program_ = 0;
program->vsh_ = 0;
@ -60,8 +62,12 @@ GLSLProgram *glsl_create_source(const char *vshader_src, const char *fshader_src
strcpy(program->name, "[srcshader]");
strcpy(program->vshader_filename, "");
strcpy(program->fshader_filename, "");
if (glsl_recompile(program)) {
if (glsl_recompile(program, error_message)) {
active_programs.insert(program);
} else {
ELOG("Failed compiling GLSL program from source strings");
delete program;
return 0;
}
register_gl_resource_holder(program);
return program;
@ -89,7 +95,7 @@ void glsl_refresh() {
}
}
bool glsl_recompile(GLSLProgram *program) {
bool glsl_recompile(GLSLProgram *program, std::string *error_message) {
struct stat vs, fs;
if (0 == stat(program->vshader_filename, &vs))
program->vshader_mtime = vs.st_mtime;
@ -125,14 +131,14 @@ bool glsl_recompile(GLSLProgram *program) {
GLuint vsh = glCreateShader(GL_VERTEX_SHADER);
const GLchar *vsh_str = program->vshader_source ? program->vshader_source : (const GLchar *)(vsh_src);
if (!CompileShader(vsh_str, vsh, program->vshader_filename)) {
if (!CompileShader(vsh_str, vsh, program->vshader_filename, error_message)) {
return false;
}
delete [] vsh_src;
const GLchar *fsh_str = program->fshader_source ? program->fshader_source : (const GLchar *)(fsh_src);
GLuint fsh = glCreateShader(GL_FRAGMENT_SHADER);
if (!CompileShader(fsh_str, fsh, program->fshader_filename)) {
if (!CompileShader(fsh_str, fsh, program->fshader_filename, error_message)) {
glDeleteShader(vsh);
return false;
}
@ -150,14 +156,20 @@ bool glsl_recompile(GLSLProgram *program) {
GLint bufLength = 0;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &bufLength);
if (bufLength) {
char* buf = new char[bufLength];
char* buf = new char[bufLength + 1]; // safety
glGetProgramInfoLog(prog, bufLength, NULL, buf);
ILOG("vsh: %i fsh: %i", vsh, fsh);
FLOG("Could not link shader program (linkstatus=%i):\n %s \n", linkStatus, buf);
delete [] buf; // we're dead!
ELOG("Could not link shader program (linkstatus=%i):\n %s \n", linkStatus, buf);
if (error_message) {
*error_message = buf;
}
delete [] buf;
} else {
ILOG("vsh: %i fsh: %i", vsh, fsh);
FLOG("Could not link shader program (linkstatus=%i). No OpenGL error log was available.", linkStatus);
ELOG("Could not link shader program (linkstatus=%i). No OpenGL error log was available.", linkStatus);
if (error_message) {
*error_message = "(no error message available)";
}
}
glDeleteShader(vsh);
glDeleteShader(fsh);

View File

@ -1,10 +1,10 @@
// Utility code for loading GLSL shaders.
// Has support for auto-reload, see glsl_refresh
#ifndef _RENDER_UTIL
#define _RENDER_UTIL
#pragma once
#include <map>
#include <string>
#include <time.h>
#include "gfx/gl_lost_manager.h"
@ -46,18 +46,17 @@ struct GLSLProgram : public GfxResourceHolder {
void GLLost();
};
// C API, old skool
// C API, old skool. Not much point either...
// From files (VFS)
GLSLProgram *glsl_create(const char *vshader_file, const char *fshader_file);
GLSLProgram *glsl_create(const char *vshader_file, const char *fshader_file, std::string *error_message = 0);
// Directly from source code
GLSLProgram *glsl_create_source(const char *vshader_src, const char *fshader_src);
GLSLProgram *glsl_create_source(const char *vshader_src, const char *fshader_src, std::string *error_message = 0);
void glsl_destroy(GLSLProgram *program);
// If recompilation of the program fails, the program is untouched and error messages
// are logged and the function returns false.
bool glsl_recompile(GLSLProgram *program);
bool glsl_recompile(GLSLProgram *program, std::string *error_message = 0);
void glsl_bind(const GLSLProgram *program);
void glsl_unbind();
int glsl_attrib_loc(const GLSLProgram *program, const char *name);
@ -67,7 +66,3 @@ int glsl_uniform_loc(const GLSLProgram *program, const char *name);
// fstat-s all the source files of all the shaders to see if they
// should be recompiled, and recompiles them if so.
void glsl_refresh();
// Use glUseProgramObjectARB(NULL); to unset.
#endif // _RENDER_UTIL