From 866532360c75298c88dc51724e878255295b98df Mon Sep 17 00:00:00 2001 From: Antony Riakiotakis Date: Thu, 9 Apr 2015 20:20:33 +0200 Subject: Fix T31546 fragment program gets created every frame That was really crappy indeed. Now we have a separate API for low level OpenGL programs, plus a nice interface for GPU, also removes some GL calls from main code as a plus :) The source for the programs is also moved to nice external .glsl files (not sure which extension convention GPU assemply uses) --- source/blender/gpu/CMakeLists.txt | 5 + source/blender/gpu/GPU_extensions.h | 25 ++++- source/blender/gpu/SConscript | 2 + source/blender/gpu/intern/gpu_extensions.c | 115 ++++++++++++++++++++- .../gpu/shaders/gpu_program_smoke_color_frag.glsl | 32 ++++++ .../gpu/shaders/gpu_program_smoke_frag.glsl | 27 +++++ 6 files changed, 200 insertions(+), 6 deletions(-) create mode 100644 source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl create mode 100644 source/blender/gpu/shaders/gpu_program_smoke_frag.glsl (limited to 'source/blender/gpu') diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 97b0e7e1e0e..23a2b77d1e7 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -57,6 +57,9 @@ set(SRC intern/gpu_compositing.c intern/gpu_debug.c + shaders/gpu_program_smoke_frag.glsl + shaders/gpu_program_smoke_color_frag.glsl + shaders/gpu_shader_fx_lib.glsl shaders/gpu_shader_fx_ssao_frag.glsl shaders/gpu_shader_fx_dof_frag.glsl @@ -89,6 +92,8 @@ set(SRC intern/gpu_private.h ) +data_to_c_simple(shaders/gpu_program_smoke_frag.glsl SRC) +data_to_c_simple(shaders/gpu_program_smoke_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_material.glsl SRC) data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_vert.glsl SRC) diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index de0af815bf4..27a4396e5d8 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -52,6 +52,9 @@ typedef struct GPUOffScreen GPUOffScreen; struct GPUShader; typedef struct GPUShader GPUShader; +struct GPUProgram; +typedef struct GPUProgram GPUProgram; + /* GPU extensions support */ void GPU_extensions_disable(void); @@ -181,6 +184,18 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels); int GPU_offscreen_width(const GPUOffScreen *ofs); int GPU_offscreen_height(const GPUOffScreen *ofs); +/* Builtin/Non-generated shaders */ +typedef enum GPUProgramType { + GPU_PROGRAM_TYPE_FRAGMENT = 0 +} GPUProgramType; + + +GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code); +void GPU_program_free(GPUProgram *program); +void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w); +void GPU_program_bind(GPUProgram *); +void GPU_program_unbind(GPUProgram *); + /* GPU Shader * - only for fragment shaders now * - must call texture bind before setting a texture as uniform! */ @@ -205,11 +220,17 @@ int GPU_shader_get_attribute(GPUShader *shader, const char *name); /* Builtin/Non-generated shaders */ typedef enum GPUBuiltinShader { - GPU_SHADER_VSM_STORE = (1<<0), - GPU_SHADER_SEP_GAUSSIAN_BLUR = (1<<1), + GPU_SHADER_VSM_STORE = 0, + GPU_SHADER_SEP_GAUSSIAN_BLUR = 1, } GPUBuiltinShader; +typedef enum GPUBuiltinProgram { + GPU_PROGRAM_SMOKE = 0, + GPU_PROGRAM_SMOKE_COLORED = 1, +} GPUBuiltinProgram; + GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader); +GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program); GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp); void GPU_shader_free_builtin_shaders(void); diff --git a/source/blender/gpu/SConscript b/source/blender/gpu/SConscript index 8d0ef394a06..ff5fb42c021 100644 --- a/source/blender/gpu/SConscript +++ b/source/blender/gpu/SConscript @@ -63,6 +63,8 @@ if env['WITH_BF_DDS']: # generated data files import os sources.extend(( + os.path.join(env['DATA_SOURCES'], "gpu_program_smoke_frag.glsl.c"), + os.path.join(env['DATA_SOURCES'], "gpu_program_smoke_color_frag.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_simple_frag.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_simple_vert.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_ssao_frag.glsl.c"), diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 363e19908e5..e8595ecc67c 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -77,6 +77,8 @@ */ /* 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[]; @@ -94,6 +96,8 @@ extern char datatoc_gpu_shader_fx_lib_glsl[]; typedef struct GPUShaders { 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]; } GPUShaders; @@ -1430,7 +1434,13 @@ struct GPUShader { int uniforms; /* required uniforms */ }; -static void shader_print_errors(const char *task, char *log, const char **code, int totcode) +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; @@ -1504,6 +1514,70 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH]) 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) +{ + 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) { GLint status; @@ -1824,6 +1898,29 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader 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: %d\n", program); + + return retval; +} + #define MAX_DEFINES 100 GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp) @@ -1905,18 +2002,28 @@ void GPU_shader_free_builtin_shaders(void) int i; if (GG.shaders.vsm_store) { - MEM_freeN(GG.shaders.vsm_store); + GPU_shader_free(GG.shaders.vsm_store); GG.shaders.vsm_store = NULL; } if (GG.shaders.sep_gaussian_blur) { - MEM_freeN(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]) { - MEM_freeN(GG.shaders.fx_shaders[i]); + GPU_shader_free(GG.shaders.fx_shaders[i]); GG.shaders.fx_shaders[i] = NULL; } } diff --git a/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl b/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl new file mode 100644 index 00000000000..a94c823f408 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl @@ -0,0 +1,32 @@ +!!ARBfp1.0 +PARAM dx = program.local[0]; +PARAM darkness = program.local[1]; +PARAM render = program.local[2]; +PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041}; +TEMP temp, shadow, flame, spec, value; +TEX temp, fragment.texcoord[0], texture[0], 3D; +TEX shadow, fragment.texcoord[0], texture[1], 3D; +TEX flame, fragment.texcoord[0], texture[2], 3D; +TEX spec, flame.r, texture[3], 1D; +# unpremultiply volume texture +RCP value.r, temp.a; +MUL temp.r, temp.r, value.r; +MUL temp.g, temp.g, value.r; +MUL temp.b, temp.b, value.r; +# calculate shading factor from density +MUL value.r, temp.a, darkness.a; +MUL value.r, value.r, dx.r; +MUL value.r, value.r, f.r; +EX2 value.r, -value.r; +# alpha +SUB temp.a, 1.0, value.r; +# shade colors +MUL temp.r, temp.r, shadow.r; +MUL temp.g, temp.g, shadow.r; +MUL temp.b, temp.b, shadow.r; +MUL temp.r, temp.r, value.r; +MUL temp.g, temp.g, value.r; +MUL temp.b, temp.b, value.r; +# for now this just replace smoke shading if rendering fire +CMP result.color, render.r, temp, spec; +END diff --git a/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl b/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl new file mode 100644 index 00000000000..04b171d24bd --- /dev/null +++ b/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl @@ -0,0 +1,27 @@ +!!ARBfp1.0 +PARAM dx = program.local[0]; +PARAM darkness = program.local[1]; +PARAM render = program.local[2]; +PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01}; +TEMP temp, shadow, flame, spec, value; +TEX temp, fragment.texcoord[0], texture[0], 3D; +TEX shadow, fragment.texcoord[0], texture[1], 3D; +TEX flame, fragment.texcoord[0], texture[2], 3D; +TEX spec, flame.r, texture[3], 1D; +# calculate shading factor from density +MUL value.r, temp.a, darkness.a; +MUL value.r, value.r, dx.r; +MUL value.r, value.r, f.r; +EX2 temp, -value.r; +# alpha +SUB temp.a, 1.0, temp.r; +# shade colors +MUL temp.r, temp.r, shadow.r; +MUL temp.g, temp.g, shadow.r; +MUL temp.b, temp.b, shadow.r; +MUL temp.r, temp.r, darkness.r; +MUL temp.g, temp.g, darkness.g; +MUL temp.b, temp.b, darkness.b; +# for now this just replace smoke shading if rendering fire +CMP result.color, render.r, temp, spec; +END -- cgit v1.2.3