nkeynes@635: /** nkeynes@635: * $Id$ nkeynes@635: * nkeynes@1130: * GLSL wrapper code to hide the differences between the different gl/sl APIs. nkeynes@1130: * nkeynes@1130: * Copyright (c) 2007-2010 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@1130: #include nkeynes@1130: nkeynes@635: #include "lxdream.h" nkeynes@635: #include "display.h" nkeynes@635: #include "pvr2/glutil.h" nkeynes@1207: #include "pvr2/shaders.h" nkeynes@635: nkeynes@635: #define MAX_ERROR_BUF 4096 nkeynes@1130: #define INVALID_SHADER 0 nkeynes@1130: #define INVALID_PROGRAM 0 nkeynes@1130: nkeynes@1130: #ifdef HAVE_OPENGL_SHADER_ARB nkeynes@1130: typedef GLhandleARB gl_program_t; nkeynes@1130: typedef GLhandleARB gl_shader_t; nkeynes@1130: #else nkeynes@1130: typedef GLuint gl_program_t; nkeynes@1130: typedef GLuint gl_shader_t; nkeynes@1130: #endif nkeynes@1130: nkeynes@1130: gboolean glsl_is_supported(); nkeynes@1130: gl_shader_t glsl_create_vertex_shader( const char *source ); nkeynes@1130: gl_shader_t glsl_create_fragment_shader( const char *source ); nkeynes@1130: gl_program_t glsl_create_program( gl_shader_t *shaderv ); nkeynes@1130: void glsl_use_program(gl_program_t program); nkeynes@1130: void glsl_destroy_shader(gl_shader_t shader); nkeynes@1130: void glsl_destroy_program(gl_program_t program); nkeynes@1130: nkeynes@1208: typedef void (*program_cleanup_fn_t)(); nkeynes@1208: static void glsl_set_cleanup_fn( program_cleanup_fn_t ); nkeynes@1208: nkeynes@1130: #ifdef HAVE_OPENGL_SHADER_ARB nkeynes@635: nkeynes@635: gboolean glsl_is_supported() nkeynes@635: { nkeynes@1248: return isOpenGLES2() || (isGLExtensionSupported("GL_ARB_fragment_shader") && nkeynes@736: isGLExtensionSupported("GL_ARB_vertex_shader") && nkeynes@1248: isGLExtensionSupported("GL_ARB_shading_language_100")); nkeynes@635: } nkeynes@635: nkeynes@1134: const char *glsl_get_version() nkeynes@1134: { nkeynes@1134: return glGetString(GL_SHADING_LANGUAGE_VERSION_ARB); nkeynes@1134: } nkeynes@1134: 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@736: glsl_print_error(msg, obj); nkeynes@736: 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@736: glsl_print_error(msg, obj); nkeynes@635: } nkeynes@635: return TRUE; nkeynes@635: } nkeynes@635: nkeynes@1130: gl_shader_t glsl_create_vertex_shader( const char *source ) nkeynes@1130: { nkeynes@1130: gboolean ok; nkeynes@1130: gl_shader_t shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); nkeynes@635: nkeynes@1130: glShaderSourceARB( shader, 1, &source, NULL ); nkeynes@1130: glCompileShaderARB(shader); nkeynes@1130: ok = glsl_check_shader_error("Failed to compile vertex shader", shader); nkeynes@1130: if( !ok ) { nkeynes@1130: glDeleteObjectARB(shader); nkeynes@1130: return INVALID_SHADER; nkeynes@635: } else { nkeynes@1130: return shader; nkeynes@635: } nkeynes@635: } nkeynes@635: nkeynes@1130: gl_shader_t glsl_create_fragment_shader( const char *source ) nkeynes@635: { nkeynes@1130: gboolean ok; nkeynes@1130: gl_shader_t shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); nkeynes@1130: nkeynes@1130: glShaderSourceARB( shader, 1, &source, NULL ); nkeynes@1130: glCompileShaderARB(shader); nkeynes@1130: ok = glsl_check_shader_error("Failed to compile fragment shader", shader); nkeynes@1130: if( !ok ) { nkeynes@1130: glDeleteObjectARB(shader); nkeynes@1130: return INVALID_SHADER; nkeynes@1130: } else { nkeynes@1130: return shader; nkeynes@1130: } nkeynes@1130: } nkeynes@1130: nkeynes@1130: gl_program_t glsl_create_program( gl_shader_t *shaderv ) nkeynes@1130: { nkeynes@1130: gboolean ok; nkeynes@1130: unsigned i; nkeynes@1130: gl_program_t program = glCreateProgramObjectARB(); nkeynes@1130: nkeynes@1130: for( i=0; shaderv[i] != INVALID_SHADER; i++ ) { nkeynes@1130: glAttachObjectARB(program, shaderv[i]); nkeynes@1130: } nkeynes@1130: nkeynes@1130: glLinkProgramARB(program); nkeynes@1130: ok = glsl_check_program_error( "Failed to link shader program", program ); nkeynes@1130: if( !ok ) { nkeynes@1130: glDeleteObjectARB(program); nkeynes@1130: return INVALID_PROGRAM; nkeynes@1130: } else { nkeynes@1130: return program; nkeynes@1130: } nkeynes@1130: } nkeynes@1130: nkeynes@1130: void glsl_use_program(gl_program_t program) nkeynes@1130: { nkeynes@1130: glUseProgramObjectARB(program); nkeynes@1130: } nkeynes@1130: nkeynes@1130: void glsl_destroy_shader(gl_shader_t shader) nkeynes@1130: { nkeynes@1130: glDeleteObjectARB(shader); nkeynes@1130: } nkeynes@1130: nkeynes@1130: void glsl_destroy_program(gl_program_t program) nkeynes@1130: { nkeynes@1130: glDeleteObjectARB(program); nkeynes@635: } nkeynes@635: nkeynes@1207: static inline GLint glsl_get_uniform_location(gl_program_t program, const char *name) nkeynes@1140: { nkeynes@1140: return glGetUniformLocationARB(program, name); nkeynes@1140: } nkeynes@1140: nkeynes@1207: static inline GLint glsl_get_attrib_location(gl_program_t program, const char *name) nkeynes@1206: { nkeynes@1206: return glGetAttribLocationARB(program, name); nkeynes@1206: } nkeynes@1206: nkeynes@1207: #define glsl_set_uniform_sampler1D(id,v) glUniform1iARB(id,v) nkeynes@1207: #define glsl_set_uniform_sampler2D(id,v) glUniform1iARB(id,v) nkeynes@1229: #define glsl_set_uniform_float(id,v) glUniform1fARB(id,v) nkeynes@1240: #define glsl_set_uniform_vec2(id,v) glUniform2fvARB(id,1,v) nkeynes@1209: #define glsl_set_uniform_vec3(id,v) glUniform3fvARB(id,1,v) nkeynes@1207: #define glsl_set_uniform_vec4(id,v) glUniform4fvARB(id,1,v) nkeynes@1207: #define glsl_set_uniform_mat4(id,v) glUniformMatrix4fvARB(id,1,GL_FALSE,v) nkeynes@1240: #define glsl_set_attrib_vec2(id,stride,v) glVertexAttribPointerARB(id, 2, GL_FLOAT, GL_FALSE, stride, v) nkeynes@1207: #define glsl_set_attrib_vec3(id,stride,v) glVertexAttribPointerARB(id, 3, GL_FLOAT, GL_FALSE, stride, v) nkeynes@1207: #define glsl_set_attrib_vec4(id,stride,v) glVertexAttribPointerARB(id, 4, GL_FLOAT, GL_FALSE, stride, v) nkeynes@1208: #define glsl_enable_attrib(id) glEnableVertexAttribArrayARB(id) nkeynes@1208: #define glsl_disable_attrib(id) glDisableVertexAttribArrayARB(id) nkeynes@1206: nkeynes@656: #elif HAVE_OPENGL_SHADER nkeynes@1130: nkeynes@1130: gboolean glsl_is_supported() nkeynes@1130: { nkeynes@1248: return isOpenGLES2() || (isGLExtensionSupported("GL_ARB_fragment_shader") && nkeynes@1130: isGLExtensionSupported("GL_ARB_vertex_shader") && nkeynes@1248: isGLExtensionSupported("GL_ARB_shading_language_100")); nkeynes@1130: } nkeynes@635: nkeynes@1134: const char *glsl_get_version() nkeynes@1134: { nkeynes@1134: return glGetString(GL_SHADING_LANGUAGE_VERSION); nkeynes@1134: } nkeynes@1134: 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@736: char buf[MAX_ERROR_BUF]; nkeynes@736: GLsizei length; nkeynes@736: glGetShaderInfoLog( shader, sizeof(buf), &length, buf ); nkeynes@736: ERROR( "%s: %s", msg, buf ); nkeynes@736: return FALSE; nkeynes@635: } nkeynes@635: return TRUE; nkeynes@635: } nkeynes@1130: nkeynes@635: gboolean glsl_check_program_error( char *msg, GLuint program ) nkeynes@635: { nkeynes@635: if( glGetError() != GL_NO_ERROR ) { nkeynes@736: char buf[MAX_ERROR_BUF]; nkeynes@736: GLsizei length; nkeynes@736: glGetProgramInfoLog( program, sizeof(buf), &length, buf ); nkeynes@736: ERROR( "%s: %s", msg, buf ); nkeynes@736: return FALSE; nkeynes@635: } nkeynes@635: return TRUE; nkeynes@635: } nkeynes@635: nkeynes@1130: gl_shader_t glsl_create_vertex_shader( const char *source ) nkeynes@635: { nkeynes@1130: gboolean ok; nkeynes@1130: gl_shader_t shader = glCreateShader(GL_VERTEX_SHADER); nkeynes@635: nkeynes@1130: glShaderSource( shader, 1, &source, NULL ); nkeynes@1130: glCompileShader(shader); nkeynes@1203: ok = glsl_check_shader_error( "Failed to compile vertex shader", shader ); nkeynes@1130: if( !ok ) { nkeynes@1130: glDeleteShader(shader); nkeynes@1130: return INVALID_SHADER; nkeynes@1130: } else { nkeynes@1130: return shader; nkeynes@635: } nkeynes@635: nkeynes@1130: } nkeynes@635: nkeynes@1130: gl_shader_t glsl_create_fragment_shader( const char *source ) nkeynes@1130: { nkeynes@1130: gboolean ok; nkeynes@1130: gl_shader_t shader = glCreateShader(GL_FRAGMENT_SHADER); nkeynes@1130: nkeynes@1130: glShaderSource( shader, 1, &source, NULL ); nkeynes@1130: glCompileShader(shader); nkeynes@1203: ok = glsl_check_shader_error( "Failed to compile fragment shader", shader ); nkeynes@1130: if( !ok ) { nkeynes@1130: glDeleteShader(shader); nkeynes@1130: return INVALID_SHADER; nkeynes@1130: } else { nkeynes@1130: return shader; nkeynes@635: } nkeynes@1130: } nkeynes@1130: nkeynes@1130: gl_program_t glsl_create_program( gl_shader_t *shaderv ) nkeynes@1130: { nkeynes@1130: gboolean ok; nkeynes@1130: unsigned i; nkeynes@1130: gl_program_t program = glCreateProgram(); nkeynes@1130: nkeynes@1130: for( i=0; shaderv[i] != INVALID_SHADER; i++ ) { nkeynes@1130: glAttachShader(program, shaderv[i]); nkeynes@1130: } nkeynes@1130: glLinkProgram(program); nkeynes@1130: ok = glsl_check_program_error( "Failed to link shader program", program ); nkeynes@1130: if( !ok ) { nkeynes@1130: glDeleteProgram(program); nkeynes@1130: return INVALID_PROGRAM; nkeynes@1130: } else { nkeynes@1130: return program; nkeynes@1130: } nkeynes@1130: } nkeynes@1130: nkeynes@1130: void glsl_use_program(gl_program_t program) nkeynes@1130: { nkeynes@1130: glUseProgram(program); nkeynes@1130: } nkeynes@1130: nkeynes@1130: void glsl_destroy_shader(gl_shader_t shader) nkeynes@1130: { nkeynes@1130: glDeleteShader(shader); nkeynes@1130: } nkeynes@1130: nkeynes@1130: void glsl_destroy_program(gl_program_t program) nkeynes@1130: { nkeynes@1130: glDeleteProgram(program); nkeynes@1130: } nkeynes@1130: nkeynes@1207: static inline GLint glsl_get_uniform_location(gl_program_t program, const char *name) nkeynes@1140: { nkeynes@1140: return glGetUniformLocation(program, name); nkeynes@1140: } nkeynes@1207: static inline GLint glsl_get_attrib_location(gl_program_t program, const char *name) nkeynes@1206: { nkeynes@1206: return glGetAttribLocation(program, name); nkeynes@1206: } nkeynes@1207: nkeynes@1207: #define glsl_set_uniform_sampler1D(id,v) glUniform1i(id,v) nkeynes@1207: #define glsl_set_uniform_sampler2D(id,v) glUniform1i(id,v) nkeynes@1229: #define glsl_set_uniform_float(id,v) glUniform1f(id,v) nkeynes@1240: #define glsl_set_uniform_vec2(id,v) glUniform2fv(id,1,v) nkeynes@1209: #define glsl_set_uniform_vec3(id,v) glUniform3fv(id,1,v) nkeynes@1207: #define glsl_set_uniform_vec4(id,v) glUniform4fv(id,1,v) nkeynes@1207: #define glsl_set_uniform_mat4(id,v) glUniformMatrix4fv(id,1,GL_FALSE,v) nkeynes@1240: #define glsl_set_attrib_vec2(id,stride,v) glVertexAttribPointer(id, 2, GL_FLOAT, GL_FALSE, stride, v) nkeynes@1207: #define glsl_set_attrib_vec3(id,stride,v) glVertexAttribPointer(id, 3, GL_FLOAT, GL_FALSE, stride, v) nkeynes@1207: #define glsl_set_attrib_vec4(id,stride,v) glVertexAttribPointer(id, 4, GL_FLOAT, GL_FALSE, stride, v) nkeynes@1208: #define glsl_enable_attrib(id) glEnableVertexAttribArray(id) nkeynes@1208: #define glsl_disable_attrib(id) glDisableVertexAttribArray(id) nkeynes@1207: nkeynes@1207: nkeynes@1130: #else nkeynes@1130: gboolean glsl_is_supported() nkeynes@1130: { nkeynes@1130: return FALSE; nkeynes@1130: } nkeynes@1130: nkeynes@1203: const char *glsl_get_version() nkeynes@1134: { nkeynes@1134: return 0; nkeynes@1134: } nkeynes@1134: nkeynes@1130: gl_shader_t glsl_create_vertex_shader( const char *source ) nkeynes@1130: { nkeynes@1130: return 0; nkeynes@1130: } nkeynes@1130: nkeynes@1130: gl_shader_t glsl_create_fragment_shader( const char *source ) nkeynes@1130: { nkeynes@1130: return 0; nkeynes@1130: } nkeynes@1130: nkeynes@1203: gl_program_t glsl_create_program( gl_shader_t *shaderv ) nkeynes@1130: { nkeynes@1130: return 0; nkeynes@1130: } nkeynes@1130: nkeynes@1130: void glsl_use_program(gl_program_t program) nkeynes@1130: { nkeynes@1130: } nkeynes@1130: nkeynes@1130: void glsl_destroy_shader(gl_shader_t shader) nkeynes@1130: { nkeynes@1130: } nkeynes@1130: nkeynes@1130: void glsl_destroy_program(gl_program_t program) nkeynes@1130: { nkeynes@1130: } nkeynes@1140: nkeynes@1207: static inline GLint glsl_get_uniform_location(gl_program_t program, const char *name) nkeynes@1140: { nkeynes@1140: return 0; nkeynes@1140: } nkeynes@1140: nkeynes@1207: static inline GLint glsl_get_attrib_location(gl_program_t program, const char *name) nkeynes@1206: { nkeynes@1206: return 0; nkeynes@1206: } nkeynes@1207: nkeynes@1229: #define glsl_set_uniform_sampler1D(id,v) nkeynes@1207: #define glsl_set_uniform_sampler2D(id,v) nkeynes@1229: #define glsl_set_uniform_float(id,v) nkeynes@1240: #define glsl_set_uniform_vec2(id,v) nkeynes@1209: #define glsl_set_uniform_vec3(id,v) nkeynes@1207: #define glsl_set_uniform_vec4(id,v) nkeynes@1207: #define glsl_set_uniform_mat4(id,v) nkeynes@1240: #define glsl_set_attrib_vec2(id,stride,v) nkeynes@1207: #define glsl_set_attrib_vec3(id,stride,v) nkeynes@1207: #define glsl_set_attrib_vec4(id,stride,v) nkeynes@1208: #define glsl_enable_attrib(id) nkeynes@1208: #define glsl_disable_attrib(id) nkeynes@1207: nkeynes@1207: nkeynes@1130: #endif nkeynes@1130: nkeynes@1130: /****************************************************************************/ nkeynes@1130: nkeynes@1208: program_cleanup_fn_t current_cleanup_fn = NULL; nkeynes@1208: nkeynes@1130: /* Pull in the auto-generated shader definitions */ nkeynes@1130: nkeynes@1130: #include "pvr2/shaders.def" nkeynes@1130: nkeynes@1130: static gl_program_t program_array[GLSL_NUM_PROGRAMS]; nkeynes@1130: nkeynes@1208: nkeynes@1130: gboolean glsl_load_shaders() nkeynes@1130: { nkeynes@1130: gl_shader_t shader_array[GLSL_NUM_SHADERS]; nkeynes@1130: gboolean ok = TRUE; nkeynes@1130: unsigned i, j; nkeynes@1130: for( i=0; i