diff options
Diffstat (limited to 'source/blender/gpu/intern/gpu_shader.c')
-rw-r--r-- | source/blender/gpu/intern/gpu_shader.c | 783 |
1 files changed, 783 insertions, 0 deletions
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c new file mode 100644 index 00000000000..83413dfdcb1 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader.c @@ -0,0 +1,783 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Brecht Van Lommel. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_math_base.h" +#include "BLI_math_vector.h" + +#include "BKE_global.h" + +#include "GPU_compositing.h" +#include "GPU_debug.h" +#include "GPU_extensions.h" +#include "GPU_glew.h" +#include "GPU_shader.h" +#include "GPU_texture.h" + +/* TODO(sergey): Find better default values for this constants. */ +#define MAX_DEFINE_LENGTH 1024 +#define MAX_EXT_DEFINE_LENGTH 1024 + +/* Non-generated shaders */ +extern char datatoc_gpu_program_smoke_frag_glsl[]; +extern char datatoc_gpu_program_smoke_color_frag_glsl[]; +extern char datatoc_gpu_shader_vsm_store_vert_glsl[]; +extern char datatoc_gpu_shader_vsm_store_frag_glsl[]; +extern char datatoc_gpu_shader_sep_gaussian_blur_vert_glsl[]; +extern char datatoc_gpu_shader_sep_gaussian_blur_frag_glsl[]; +extern char datatoc_gpu_shader_fx_vert_glsl[]; +extern char datatoc_gpu_shader_fx_ssao_frag_glsl[]; +extern char datatoc_gpu_shader_fx_dof_frag_glsl[]; +extern char datatoc_gpu_shader_fx_dof_vert_glsl[]; +extern char datatoc_gpu_shader_fx_dof_hq_frag_glsl[]; +extern char datatoc_gpu_shader_fx_dof_hq_vert_glsl[]; +extern char datatoc_gpu_shader_fx_dof_hq_geo_glsl[]; +extern char datatoc_gpu_shader_fx_depth_resolve_glsl[]; +extern char datatoc_gpu_shader_fx_lib_glsl[]; + +static struct GPUShadersGlobal { + struct { + GPUShader *vsm_store; + GPUShader *sep_gaussian_blur; + GPUProgram *smoke; + GPUProgram *smoke_colored; + /* cache for shader fx. Those can exist in combinations so store them here */ + GPUShader *fx_shaders[MAX_FX_SHADERS * 2]; + } shaders; +} GG = {{NULL}}; + +/* GPUShader */ + +struct GPUShader { + GLuint program; /* handle for full program (links shader stages below) */ + + GLuint vertex; /* handle for vertex shader */ + GLuint geometry; /* handle for geometry shader */ + GLuint fragment; /* handle for fragment shader */ + + int totattrib; /* total number of attributes */ + int uniforms; /* required uniforms */ +}; + +struct GPUProgram { + GPUProgramType type; + GLuint prog; +}; + +static void shader_print_errors(const char *task, const char *log, const char **code, int totcode) +{ + int i; + int line = 1; + + fprintf(stderr, "GPUShader: %s error:\n", task); + + for (i = 0; i < totcode; i++) { + const char *c, *pos, *end = code[i] + strlen(code[i]); + + if (G.debug & G_DEBUG) { + fprintf(stderr, "===== shader string %d ====\n", i + 1); + + c = code[i]; + while ((c < end) && (pos = strchr(c, '\n'))) { + fprintf(stderr, "%2d ", line); + fwrite(c, (pos + 1) - c, 1, stderr); + c = pos + 1; + line++; + } + + fprintf(stderr, "%s", c); + } + } + + fprintf(stderr, "%s\n", log); +} + +static const char *gpu_shader_version(void) +{ + if (GLEW_VERSION_3_2) { + if (GLEW_ARB_compatibility) { + return "#version 150 compatibility\n"; + /* highest version that is widely supported + * gives us native geometry shaders! + * use compatibility profile so we can continue using builtin shader input/output names + */ + } + else { + return "#version 130\n"; + /* latest version that is compatible with existing shaders */ + } + } + else if (GLEW_VERSION_3_1) { + if (GLEW_ARB_compatibility) { + return "#version 140\n"; + /* also need the ARB_compatibility extension, handled below */ + } + else { + return "#version 130\n"; + /* latest version that is compatible with existing shaders */ + } + } + else if (GLEW_VERSION_3_0) { + return "#version 130\n"; + /* GLSL 1.3 has modern syntax/keywords/datatypes so use if available + * older features are deprecated but still available without compatibility extension or profile + */ + } + else { + return "#version 120\n"; + /* minimum supported */ + } +} + + +static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH], bool use_geometry_shader) +{ + /* enable extensions for features that are not part of our base GLSL version + * don't use an extension for something already available! + */ + + if (GLEW_ARB_texture_query_lod) { + /* a #version 400 feature, but we use #version 150 maximum so use extension */ + strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n"); + } + + if (use_geometry_shader && GPU_geometry_shader_support_via_extension()) { + strcat(defines, "#extension GL_EXT_geometry_shader4: enable\n"); + } + + if (GLEW_VERSION_3_1 && !GLEW_VERSION_3_2 && GLEW_ARB_compatibility) { + strcat(defines, "#extension GL_ARB_compatibility: enable\n"); + } + + if (!GLEW_VERSION_3_1) { + if (GLEW_ARB_draw_instanced) { + strcat(defines, "#extension GL_ARB_draw_instanced: enable\n"); + } + + if (!GLEW_VERSION_3_0 && GLEW_EXT_gpu_shader4) { + strcat(defines, "#extension GL_EXT_gpu_shader4: enable\n"); + /* TODO: maybe require this? shaders become so much nicer */ + } + } +} + +static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH], bool use_opensubdiv) +{ + /* some useful defines to detect GPU type */ + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) { + strcat(defines, "#define GPU_ATI\n"); + if (GLEW_VERSION_3_0) { + /* TODO(merwin): revisit this version check; GLEW_VERSION_3_0 means GL 3.0 or newer */ + strcat(defines, "#define CLIP_WORKAROUND\n"); + } + } + else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) + strcat(defines, "#define GPU_NVIDIA\n"); + else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) + strcat(defines, "#define GPU_INTEL\n"); + + if (GPU_bicubic_bump_support()) + strcat(defines, "#define BUMP_BICUBIC\n"); + +#ifdef WITH_OPENSUBDIV + /* TODO(sergey): Check whether we actually compiling shader for + * the OpenSubdiv mesh. + */ + if (use_opensubdiv) { + strcat(defines, "#define USE_OPENSUBDIV\n"); + + /* TODO(sergey): not strictly speaking a define, but this is + * a global typedef which we don't have better place to define + * in yet. + */ + strcat(defines, "struct VertexData {\n" + " vec4 position;\n" + " vec3 normal;\n" + " vec2 uv;" + "};\n"); + } +#else + UNUSED_VARS(use_opensubdiv); +#endif + + return; +} + +void GPU_program_bind(GPUProgram *program) +{ + glEnable(program->type); + glBindProgramARB(program->type, program->prog); +} + +void GPU_program_unbind(GPUProgram *program) +{ + glDisable(program->type); + glBindProgramARB(program->type, 0); +} + + +GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code) +{ + /* TODO(merwin): remove ARB program support (recode smoke shader in GLSL) */ + + GPUProgram *program; + GLint error_pos, is_native; + + if (!(GLEW_ARB_fragment_program && type == GPU_PROGRAM_TYPE_FRAGMENT)) + return NULL; + + program = MEM_callocN(sizeof(GPUProgram), "GPUProgram"); + + switch (type) { + case GPU_PROGRAM_TYPE_FRAGMENT: + program->type = GL_FRAGMENT_PROGRAM_ARB; + break; + } + + /* create the object and set its code string */ + glGenProgramsARB(1, &program->prog); + glBindProgramARB(program->type, program->prog); + + glProgramStringARB(program->type, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(code), code); + + glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos); + glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &is_native); + if ((error_pos == -1) && (is_native == 1)) { + return program; + } + else { + /* glGetError is set before that, clear it */ + while (glGetError() != GL_NO_ERROR) + ; + shader_print_errors("compile", (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB), &code, 1); + MEM_freeN(program); + } + + return NULL; +} + +void GPU_program_free(GPUProgram *program) +{ + glDeleteProgramsARB(1, &program->prog); + MEM_freeN(program); +} + +void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w) +{ + glProgramLocalParameter4fARB(program->type, location, x, y, z, w); +} + +GPUShader *GPU_shader_create(const char *vertexcode, + const char *fragcode, + const char *geocode, + const char *libcode, + const char *defines, + int input, + int output, + int number) +{ + return GPU_shader_create_ex(vertexcode, + fragcode, + geocode, + libcode, + defines, + input, + output, + number, + GPU_SHADER_FLAGS_NONE); +} + +GPUShader *GPU_shader_create_ex(const char *vertexcode, + const char *fragcode, + const char *geocode, + const char *libcode, + const char *defines, + int input, + int output, + int number, + const int flags) +{ +#ifdef WITH_OPENSUBDIV + /* TODO(sergey): used to add #version 150 to the geometry shader. + * Could safely be renamed to "use_geometry_code" since it's very + * likely any of geometry code will want to use GLSL 1.5. + */ + bool use_opensubdiv = (flags & GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV) != 0; +#else + UNUSED_VARS(flags); + bool use_opensubdiv = false; +#endif + GLint status; + GLchar log[5000]; + GLsizei length = 0; + GPUShader *shader; + char standard_defines[MAX_DEFINE_LENGTH] = ""; + char standard_extensions[MAX_EXT_DEFINE_LENGTH] = ""; + + if (geocode && !GPU_geometry_shader_support()) + return NULL; + + shader = MEM_callocN(sizeof(GPUShader), "GPUShader"); + + if (vertexcode) + shader->vertex = glCreateShader(GL_VERTEX_SHADER); + if (fragcode) + shader->fragment = glCreateShader(GL_FRAGMENT_SHADER); + if (geocode) + shader->geometry = glCreateShader(GL_GEOMETRY_SHADER_EXT); + + shader->program = glCreateProgram(); + + if (!shader->program || + (vertexcode && !shader->vertex) || + (fragcode && !shader->fragment) || + (geocode && !shader->geometry)) + { + fprintf(stderr, "GPUShader, object creation failed.\n"); + GPU_shader_free(shader); + return NULL; + } + + gpu_shader_standard_defines(standard_defines, use_opensubdiv); + gpu_shader_standard_extensions(standard_extensions, geocode != NULL); + + if (vertexcode) { + const char *source[5]; + /* custom limit, may be too small, beware */ + int num_source = 0; + + source[num_source++] = gpu_shader_version(); + source[num_source++] = standard_extensions; + source[num_source++] = standard_defines; + + if (defines) source[num_source++] = defines; + source[num_source++] = vertexcode; + + glAttachShader(shader->program, shader->vertex); + glShaderSource(shader->vertex, num_source, source, NULL); + + glCompileShader(shader->vertex); + glGetShaderiv(shader->vertex, GL_COMPILE_STATUS, &status); + + if (!status) { + glGetShaderInfoLog(shader->vertex, sizeof(log), &length, log); + shader_print_errors("compile", log, source, num_source); + + GPU_shader_free(shader); + return NULL; + } + } + + if (fragcode) { + const char *source[7]; + int num_source = 0; + + source[num_source++] = gpu_shader_version(); + source[num_source++] = standard_extensions; + source[num_source++] = standard_defines; + +#ifdef WITH_OPENSUBDIV + /* TODO(sergey): Move to fragment shader source code generation. */ + if (use_opensubdiv) { + source[num_source++] = + "#ifdef USE_OPENSUBDIV\n" + "in block {\n" + " VertexData v;\n" + "} inpt;\n" + "#endif\n"; + } +#endif + + if (defines) source[num_source++] = defines; + if (libcode) source[num_source++] = libcode; + source[num_source++] = fragcode; + + glAttachShader(shader->program, shader->fragment); + glShaderSource(shader->fragment, num_source, source, NULL); + + glCompileShader(shader->fragment); + glGetShaderiv(shader->fragment, GL_COMPILE_STATUS, &status); + + if (!status) { + glGetShaderInfoLog(shader->fragment, sizeof(log), &length, log); + shader_print_errors("compile", log, source, num_source); + + GPU_shader_free(shader); + return NULL; + } + } + + if (geocode) { + const char *source[6]; + int num_source = 0; + + source[num_source++] = gpu_shader_version(); + source[num_source++] = standard_extensions; + source[num_source++] = standard_defines; + + if (defines) source[num_source++] = defines; + source[num_source++] = geocode; + + glAttachShader(shader->program, shader->geometry); + glShaderSource(shader->geometry, num_source, source, NULL); + + glCompileShader(shader->geometry); + glGetShaderiv(shader->geometry, GL_COMPILE_STATUS, &status); + + if (!status) { + glGetShaderInfoLog(shader->geometry, sizeof(log), &length, log); + shader_print_errors("compile", log, source, num_source); + + GPU_shader_free(shader); + return NULL; + } + + if (!use_opensubdiv) { + GPU_shader_geometry_stage_primitive_io(shader, input, output, number); + } + } + +#ifdef WITH_OPENSUBDIV + if (use_opensubdiv) { + glBindAttribLocation(shader->program, 0, "position"); + glBindAttribLocation(shader->program, 1, "normal"); + GPU_shader_geometry_stage_primitive_io(shader, + GL_LINES_ADJACENCY_EXT, + GL_TRIANGLE_STRIP, + 4); + } +#endif + + glLinkProgram(shader->program); + glGetProgramiv(shader->program, GL_LINK_STATUS, &status); + if (!status) { + glGetProgramInfoLog(shader->program, sizeof(log), &length, log); + /* print attached shaders in pipeline order */ + if (vertexcode) shader_print_errors("linking", log, &vertexcode, 1); + if (geocode) shader_print_errors("linking", log, &geocode, 1); + if (libcode) shader_print_errors("linking", log, &libcode, 1); + if (fragcode) shader_print_errors("linking", log, &fragcode, 1); + + GPU_shader_free(shader); + return NULL; + } + +#ifdef WITH_OPENSUBDIV + /* TODO(sergey): Find a better place for this. */ + if (use_opensubdiv && GLEW_VERSION_4_1) { + glProgramUniform1i(shader->program, + glGetUniformLocation(shader->program, "FVarDataBuffer"), + 31); /* GL_TEXTURE31 */ + } +#endif + + return shader; +} + +void GPU_shader_bind(GPUShader *shader) +{ + GPU_ASSERT_NO_GL_ERRORS("Pre Shader Bind"); + glUseProgram(shader->program); + GPU_ASSERT_NO_GL_ERRORS("Post Shader Bind"); +} + +void GPU_shader_unbind(void) +{ + GPU_ASSERT_NO_GL_ERRORS("Pre Shader Unbind"); + glUseProgram(0); + GPU_ASSERT_NO_GL_ERRORS("Post Shader Unbind"); +} + +void GPU_shader_free(GPUShader *shader) +{ + if (shader->vertex) + glDeleteShader(shader->vertex); + if (shader->geometry) + glDeleteShader(shader->geometry); + if (shader->fragment) + glDeleteShader(shader->fragment); + if (shader->program) + glDeleteProgram(shader->program); + MEM_freeN(shader); +} + +int GPU_shader_get_uniform(GPUShader *shader, const char *name) +{ + return glGetUniformLocation(shader->program, name); +} + +void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, const float *value) +{ + if (location == -1 || value == NULL) + return; + + GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector"); + + if (length == 1) glUniform1fv(location, arraysize, value); + else if (length == 2) glUniform2fv(location, arraysize, value); + else if (length == 3) glUniform3fv(location, arraysize, value); + else if (length == 4) glUniform4fv(location, arraysize, value); + else if (length == 9) glUniformMatrix3fv(location, arraysize, 0, value); + else if (length == 16) glUniformMatrix4fv(location, arraysize, 0, value); + + GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector"); +} + +void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int length, int arraysize, const int *value) +{ + if (location == -1) + return; + + GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector"); + + if (length == 1) glUniform1iv(location, arraysize, value); + else if (length == 2) glUniform2iv(location, arraysize, value); + else if (length == 3) glUniform3iv(location, arraysize, value); + else if (length == 4) glUniform4iv(location, arraysize, value); + + GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector"); +} + +void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) +{ + if (location == -1) + return; + + GPU_CHECK_ERRORS_AROUND(glUniform1i(location, value)); +} + +void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number) +{ + if (GPU_geometry_shader_support_via_extension()) { + /* geometry shaders must provide this info themselves for #version 150 and up */ + glProgramParameteriEXT(shader->program, GL_GEOMETRY_INPUT_TYPE_EXT, input); + glProgramParameteriEXT(shader->program, GL_GEOMETRY_OUTPUT_TYPE_EXT, output); + glProgramParameteriEXT(shader->program, GL_GEOMETRY_VERTICES_OUT_EXT, number); + } +} + +void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex) +{ + GLenum arbnumber; + int number = GPU_texture_bound_number(tex); + int bindcode = GPU_texture_opengl_bindcode(tex); + int target = GPU_texture_target(tex); + + if (number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; + } + + if (number == -1) + return; + + if (location == -1) + return; + + GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Texture"); + + arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number); + + if (number != 0) glActiveTexture(arbnumber); + if (bindcode != 0) + glBindTexture(target, bindcode); + else + GPU_invalid_tex_bind(target); + glUniform1i(location, number); + glEnable(target); + if (number != 0) glActiveTexture(GL_TEXTURE0); + + GPU_ASSERT_NO_GL_ERRORS("Post Uniform Texture"); +} + +int GPU_shader_get_attribute(GPUShader *shader, const char *name) +{ + int index; + + GPU_CHECK_ERRORS_AROUND(index = glGetAttribLocation(shader->program, name)); + + return index; +} + +GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) +{ + GPUShader *retval = NULL; + + switch (shader) { + case GPU_SHADER_VSM_STORE: + if (!GG.shaders.vsm_store) + GG.shaders.vsm_store = GPU_shader_create(datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, NULL, NULL, NULL, 0, 0, 0); + retval = GG.shaders.vsm_store; + break; + case GPU_SHADER_SEP_GAUSSIAN_BLUR: + if (!GG.shaders.sep_gaussian_blur) + GG.shaders.sep_gaussian_blur = GPU_shader_create(datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, datatoc_gpu_shader_sep_gaussian_blur_frag_glsl, NULL, NULL, NULL, 0, 0, 0); + retval = GG.shaders.sep_gaussian_blur; + break; + } + + if (retval == NULL) + printf("Unable to create a GPUShader for builtin shader: %u\n", shader); + + return retval; +} + +GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program) +{ + GPUProgram *retval = NULL; + + switch (program) { + case GPU_PROGRAM_SMOKE: + if (!GG.shaders.smoke) + GG.shaders.smoke = GPU_program_shader_create(GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_frag_glsl); + retval = GG.shaders.smoke; + break; + case GPU_PROGRAM_SMOKE_COLORED: + if (!GG.shaders.smoke_colored) + GG.shaders.smoke_colored = GPU_program_shader_create(GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_color_frag_glsl); + retval = GG.shaders.smoke_colored; + break; + } + + if (retval == NULL) + printf("Unable to create a GPUProgram for builtin program: %u\n", program); + + return retval; +} + +#define MAX_DEFINES 100 + +GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp) +{ + int offset; + char defines[MAX_DEFINES] = ""; + /* avoid shaders out of range */ + if (effects >= MAX_FX_SHADERS) + return NULL; + + offset = 2 * effects; + + if (persp) { + offset += 1; + strcat(defines, "#define PERSP_MATRIX\n"); + } + + if (!GG.shaders.fx_shaders[offset]) { + GPUShader *shader; + + switch (effects) { + case GPU_SHADER_FX_SSAO: + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_ssao_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE: + strcat(defines, "#define FIRST_PASS\n"); + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO: + strcat(defines, "#define SECOND_PASS\n"); + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE: + strcat(defines, "#define THIRD_PASS\n"); + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR: + strcat(defines, "#define FOURTH_PASS\n"); + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE: + strcat(defines, "#define FIFTH_PASS\n"); + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE: + strcat(defines, "#define FIRST_PASS\n"); + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO: + strcat(defines, "#define SECOND_PASS\n"); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, datatoc_gpu_shader_fx_dof_hq_geo_glsl, datatoc_gpu_shader_fx_lib_glsl, + defines, GL_POINTS, GL_TRIANGLE_STRIP, 4); + GG.shaders.fx_shaders[offset] = shader; + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE: + strcat(defines, "#define THIRD_PASS\n"); + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + break; + + case GPU_SHADER_FX_DEPTH_RESOLVE: + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines, 0, 0, 0); + } + } + + return GG.shaders.fx_shaders[offset]; +} + + +void GPU_shader_free_builtin_shaders(void) +{ + int i; + + if (GG.shaders.vsm_store) { + GPU_shader_free(GG.shaders.vsm_store); + GG.shaders.vsm_store = NULL; + } + + if (GG.shaders.sep_gaussian_blur) { + GPU_shader_free(GG.shaders.sep_gaussian_blur); + GG.shaders.sep_gaussian_blur = NULL; + } + + if (GG.shaders.smoke) { + GPU_program_free(GG.shaders.smoke); + GG.shaders.smoke = NULL; + } + + if (GG.shaders.smoke_colored) { + GPU_program_free(GG.shaders.smoke_colored); + GG.shaders.smoke_colored = NULL; + } + + for (i = 0; i < 2 * MAX_FX_SHADERS; i++) { + if (GG.shaders.fx_shaders[i]) { + GPU_shader_free(GG.shaders.fx_shaders[i]); + GG.shaders.fx_shaders[i] = NULL; + } + } +} + + |