nkeynes@635: /** nkeynes@635: * $Id$ nkeynes@635: * nkeynes@635: * GLSL shader loader/unloader. Current version assumes there's exactly nkeynes@635: * 1 shader program that's used globally. This may turn out not to be the nkeynes@635: * most efficient approach. nkeynes@635: * nkeynes@635: * Copyright (c) 2007 Nathan Keynes. nkeynes@635: * nkeynes@635: * This program is free software; you can redistribute it and/or modify nkeynes@635: * it under the terms of the GNU General Public License as published by nkeynes@635: * the Free Software Foundation; either version 2 of the License, or nkeynes@635: * (at your option) any later version. nkeynes@635: * nkeynes@635: * This program is distributed in the hope that it will be useful, nkeynes@635: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@635: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@635: * GNU General Public License for more details. nkeynes@635: */ nkeynes@635: nkeynes@635: #include "lxdream.h" nkeynes@635: #include "display.h" nkeynes@635: #include "pvr2/glutil.h" nkeynes@635: nkeynes@635: #define MAX_ERROR_BUF 4096 nkeynes@635: nkeynes@635: gboolean glsl_is_supported() nkeynes@635: { nkeynes@635: return isGLExtensionSupported("GL_ARB_fragment_shader") && nkeynes@635: isGLExtensionSupported("GL_ARB_vertex_shader") && nkeynes@635: isGLExtensionSupported("GL_ARB_shading_language_100"); nkeynes@635: } nkeynes@635: nkeynes@635: #ifdef GL_ARB_shader_objects nkeynes@635: static GLhandleARB glsl_program = 0, glsl_vert_shader = 0, glsl_frag_shader = 0; nkeynes@635: nkeynes@635: void glsl_print_error( char *msg, GLhandleARB obj ) nkeynes@635: { nkeynes@635: char buf[MAX_ERROR_BUF]; nkeynes@635: GLsizei length; nkeynes@635: glGetInfoLogARB( obj, sizeof(buf), &length, buf ); nkeynes@635: ERROR( "%s: %s", msg, buf ); nkeynes@635: } nkeynes@635: nkeynes@635: gboolean glsl_check_shader_error( char *msg, GLhandleARB obj ) nkeynes@635: { nkeynes@635: GLint value; nkeynes@635: nkeynes@635: glGetObjectParameterivARB(obj, GL_OBJECT_COMPILE_STATUS_ARB, &value); nkeynes@635: if( value == 0 ) { nkeynes@635: glsl_print_error(msg, obj); nkeynes@635: return FALSE; nkeynes@635: } nkeynes@635: return TRUE; nkeynes@635: } nkeynes@635: nkeynes@635: gboolean glsl_check_program_error( char *msg, GLhandleARB obj ) nkeynes@635: { nkeynes@635: if( glGetError() != GL_NO_ERROR ) { nkeynes@635: glsl_print_error(msg, obj); nkeynes@635: } nkeynes@635: return TRUE; nkeynes@635: } nkeynes@635: nkeynes@635: nkeynes@635: gboolean glsl_load_shaders( const char *vertex_src, const char *fragment_src ) nkeynes@635: { nkeynes@635: gboolean vsok = TRUE, fsok = TRUE, pok = FALSE; nkeynes@635: nkeynes@635: if( vertex_src == NULL && fragment_src == NULL ) { nkeynes@635: return TRUE; // nothing to do nkeynes@635: } nkeynes@635: nkeynes@635: glsl_program = glCreateProgramObjectARB(); nkeynes@635: nkeynes@635: if( vertex_src != NULL ) { nkeynes@635: glsl_vert_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); nkeynes@635: glShaderSourceARB( glsl_vert_shader, 1, &vertex_src, NULL ); nkeynes@635: glCompileShaderARB(glsl_vert_shader); nkeynes@635: vsok = glsl_check_shader_error("Failed to compile vertex shader", glsl_vert_shader); nkeynes@635: } nkeynes@635: if( fragment_src != NULL ) { nkeynes@635: glsl_frag_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); nkeynes@635: glShaderSourceARB( glsl_frag_shader, 1, &fragment_src, NULL ); nkeynes@635: glCompileShaderARB(glsl_frag_shader); nkeynes@635: fsok = glsl_check_shader_error("Failed to compile fragment shader", glsl_frag_shader); nkeynes@635: } nkeynes@635: nkeynes@635: if( vsok && fsok ) { nkeynes@635: if( vertex_src != NULL ) { nkeynes@635: glAttachObjectARB(glsl_program, glsl_vert_shader); nkeynes@635: } nkeynes@635: if( fragment_src != NULL ) { nkeynes@635: glAttachObjectARB(glsl_program, glsl_frag_shader); nkeynes@635: } nkeynes@635: glLinkProgramARB(glsl_program); nkeynes@635: pok = glsl_check_program_error( "Failed to link shader program", glsl_program ); nkeynes@635: } nkeynes@635: if( pok ) { nkeynes@635: glUseProgramObjectARB(glsl_program); nkeynes@635: pok = glsl_check_program_error( "Failed to apply shader program", glsl_program ); nkeynes@635: } else { nkeynes@635: glsl_unload_shaders(); nkeynes@635: } nkeynes@635: return pok; nkeynes@635: } nkeynes@635: nkeynes@669: void glsl_enable_shaders(gboolean en) nkeynes@635: { nkeynes@635: if( glsl_program != 0 ) { nkeynes@635: if( en ) { nkeynes@635: glUseProgramObjectARB(glsl_program); nkeynes@635: } else { nkeynes@635: glUseProgramObjectARB(0); nkeynes@635: } nkeynes@635: } nkeynes@635: } nkeynes@635: nkeynes@635: void glsl_unload_shaders(void) nkeynes@635: { nkeynes@635: glUseProgramObjectARB(0); nkeynes@635: glDetachObjectARB(glsl_program, glsl_vert_shader); nkeynes@635: glDetachObjectARB(glsl_program, glsl_frag_shader); nkeynes@635: glDeleteObjectARB(glsl_program); nkeynes@635: glDeleteObjectARB(glsl_vert_shader); nkeynes@635: glDeleteObjectARB(glsl_frag_shader); nkeynes@635: } nkeynes@635: nkeynes@656: #elif HAVE_OPENGL_SHADER nkeynes@635: static GLuint glsl_program = 0, glsl_vert_shader = 0, glsl_frag_shader = 0; nkeynes@635: nkeynes@635: gboolean glsl_check_shader_error( char *msg, GLuint shader ) nkeynes@635: { nkeynes@635: GLint value; nkeynes@635: nkeynes@635: glGetShaderiv( shader, GL_COMPILE_STATUS, &value ); nkeynes@635: if( value == 0 ) { nkeynes@635: char buf[MAX_ERROR_BUF]; nkeynes@635: GLsizei length; nkeynes@635: glGetShaderInfoLog( shader, sizeof(buf), &length, buf ); nkeynes@635: ERROR( "%s: %s", msg, buf ); nkeynes@635: return FALSE; nkeynes@635: } nkeynes@635: return TRUE; nkeynes@635: } nkeynes@635: gboolean glsl_check_program_error( char *msg, GLuint program ) nkeynes@635: { nkeynes@635: if( glGetError() != GL_NO_ERROR ) { nkeynes@635: char buf[MAX_ERROR_BUF]; nkeynes@635: GLsizei length; nkeynes@635: glGetProgramInfoLog( program, sizeof(buf), &length, buf ); nkeynes@635: ERROR( "%s: %s", msg, buf ); nkeynes@635: return FALSE; nkeynes@635: } nkeynes@635: return TRUE; nkeynes@635: } nkeynes@635: nkeynes@635: gboolean glsl_load_shaders( const char *vertex_src, const char *fragment_src ) nkeynes@635: { nkeynes@635: gboolean vsok = TRUE, fsok = TRUE, pok = FALSE; nkeynes@635: nkeynes@635: if( vertex_src == NULL && fragment_src == NULL ) { nkeynes@635: return TRUE; nkeynes@635: } nkeynes@635: nkeynes@635: glsl_program = glCreateProgram(); nkeynes@635: nkeynes@635: if( vertex_src != NULL ) { nkeynes@635: glsl_vert_shader = glCreateShader(GL_VERTEX_SHADER); nkeynes@635: glShaderSource( glsl_vert_shader, 1, &vertex_src, NULL ); nkeynes@635: glCompileShader(glsl_vert_shader); nkeynes@635: vsok = glsl_check_shader_error( "Failed to compile vertex shader", glsl_vert_shader ); nkeynes@635: } nkeynes@635: if( fragment_src != NULL ) { nkeynes@635: glsl_frag_shader = glCreateShader(GL_FRAGMENT_SHADER); nkeynes@635: glShaderSource( glsl_frag_shader, 1, &fragment_src, NULL ); nkeynes@635: glCompileShader(glsl_frag_shader); nkeynes@635: fsok = glsl_check_shader_error( "Failed to compile fragment shader", glsl_frag_shader ); nkeynes@635: } nkeynes@635: nkeynes@635: if( vsok && fsok ) { nkeynes@635: if( vertex_src != NULL ) { nkeynes@635: glAttachShader(glsl_program, glsl_vert_shader); nkeynes@635: } nkeynes@635: if( fragment_src != NULL ) { nkeynes@635: glAttachShader(glsl_program, glsl_frag_shader); nkeynes@635: } nkeynes@635: glLinkProgram(glsl_program); nkeynes@635: pok = glsl_check_program_error( "Failed to link shader program", glsl_program ); nkeynes@635: } nkeynes@635: nkeynes@635: if( pok ) { nkeynes@635: glUseProgram(glsl_program); nkeynes@635: } else { nkeynes@635: glsl_unload_shaders(); nkeynes@635: } nkeynes@635: return pok; nkeynes@635: } nkeynes@635: nkeynes@635: nkeynes@669: void glsl_enable_shaders(gboolean en) nkeynes@635: { nkeynes@635: if( glsl_program != 0 ) { nkeynes@635: if( en ) { nkeynes@635: glUseProgram(glsl_program); nkeynes@635: } else { nkeynes@635: glUseProgram(0); nkeynes@635: } nkeynes@635: } nkeynes@635: } nkeynes@635: nkeynes@635: void glsl_unload_shaders(void) nkeynes@635: { nkeynes@635: glUseProgram(0); nkeynes@635: glDetachShader(glsl_program, glsl_vert_shader); nkeynes@635: glDetachShader(glsl_program, glsl_frag_shader); nkeynes@635: glDeleteProgram(glsl_program); nkeynes@635: glDeleteShader(glsl_vert_shader); nkeynes@635: glDeleteShader(glsl_frag_shader); nkeynes@635: } nkeynes@656: nkeynes@656: #else nkeynes@656: gboolean glsl_load_shaders( const char *vertex_src, const char *fragment_src ) nkeynes@656: { nkeynes@656: return FALSE; nkeynes@656: } nkeynes@656: nkeynes@656: void glsl_unload_shaders() nkeynes@656: { nkeynes@656: } nkeynes@656: nkeynes@669: void glsl_enable_shaders( gboolean enable ) nkeynes@669: { nkeynes@669: } nkeynes@635: #endif