diff options
author | Antony Riakiotakis <kalast@gmail.com> | 2015-04-09 21:20:33 +0300 |
---|---|---|
committer | Antony Riakiotakis <kalast@gmail.com> | 2015-04-09 21:20:50 +0300 |
commit | 866532360c75298c88dc51724e878255295b98df (patch) | |
tree | 31974b583480531ab8c2bcd8baff75d1ea329ac0 | |
parent | 7ea4163e1e5a33d38573371c8b19969b051d5ea2 (diff) |
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)
-rw-r--r-- | SConstruct | 3 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/drawvolume.c | 101 | ||||
-rw-r--r-- | source/blender/gpu/CMakeLists.txt | 5 | ||||
-rw-r--r-- | source/blender/gpu/GPU_extensions.h | 25 | ||||
-rw-r--r-- | source/blender/gpu/SConscript | 2 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_extensions.c | 115 | ||||
-rw-r--r-- | source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl | 32 | ||||
-rw-r--r-- | source/blender/gpu/shaders/gpu_program_smoke_frag.glsl | 27 |
8 files changed, 215 insertions, 95 deletions
diff --git a/SConstruct b/SConstruct index 7cdc4b35206..6cf3874b366 100644 --- a/SConstruct +++ b/SConstruct @@ -758,6 +758,9 @@ if B.targets != ['cudakernels']: data_to_c_simple("release/datafiles/preview_cycles.blend") # --- glsl --- + data_to_c_simple("source/blender/gpu/shaders/gpu_program_smoke_frag.glsl") + data_to_c_simple("source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl") + data_to_c_simple("source/blender/gpu/shaders/gpu_shader_simple_frag.glsl") data_to_c_simple("source/blender/gpu/shaders/gpu_shader_simple_vert.glsl") data_to_c_simple("source/blender/gpu/shaders/gpu_shader_material.glsl") diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index 92883f28836..c0d8d139ddd 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -135,76 +135,8 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, unsigned char *spec_data; float *spec_pixels; GPUTexture *tex_spec; - - /* Fragment program to calculate the view3d of smoke */ - /* using 4 textures, density, shadow, flame and flame spectrum */ - const char *shader_basic = - "!!ARBfp1.0\n" - "PARAM dx = program.local[0];\n" - "PARAM darkness = program.local[1];\n" - "PARAM render = program.local[2];\n" - "PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};\n" - "TEMP temp, shadow, flame, spec, value;\n" - "TEX temp, fragment.texcoord[0], texture[0], 3D;\n" - "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n" - "TEX flame, fragment.texcoord[0], texture[2], 3D;\n" - "TEX spec, flame.r, texture[3], 1D;\n" - /* calculate shading factor from density */ - "MUL value.r, temp.a, darkness.a;\n" - "MUL value.r, value.r, dx.r;\n" - "MUL value.r, value.r, f.r;\n" - "EX2 temp, -value.r;\n" - /* alpha */ - "SUB temp.a, 1.0, temp.r;\n" - /* shade colors */ - "MUL temp.r, temp.r, shadow.r;\n" - "MUL temp.g, temp.g, shadow.r;\n" - "MUL temp.b, temp.b, shadow.r;\n" - "MUL temp.r, temp.r, darkness.r;\n" - "MUL temp.g, temp.g, darkness.g;\n" - "MUL temp.b, temp.b, darkness.b;\n" - /* for now this just replace smoke shading if rendering fire */ - "CMP result.color, render.r, temp, spec;\n" - "END\n"; - - /* color shader */ - const char *shader_color = - "!!ARBfp1.0\n" - "PARAM dx = program.local[0];\n" - "PARAM darkness = program.local[1];\n" - "PARAM render = program.local[2];\n" - "PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041};\n" - "TEMP temp, shadow, flame, spec, value;\n" - "TEX temp, fragment.texcoord[0], texture[0], 3D;\n" - "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n" - "TEX flame, fragment.texcoord[0], texture[2], 3D;\n" - "TEX spec, flame.r, texture[3], 1D;\n" - /* unpremultiply volume texture */ - "RCP value.r, temp.a;\n" - "MUL temp.r, temp.r, value.r;\n" - "MUL temp.g, temp.g, value.r;\n" - "MUL temp.b, temp.b, value.r;\n" - /* calculate shading factor from density */ - "MUL value.r, temp.a, darkness.a;\n" - "MUL value.r, value.r, dx.r;\n" - "MUL value.r, value.r, f.r;\n" - "EX2 value.r, -value.r;\n" - /* alpha */ - "SUB temp.a, 1.0, value.r;\n" - /* shade colors */ - "MUL temp.r, temp.r, shadow.r;\n" - "MUL temp.g, temp.g, shadow.r;\n" - "MUL temp.b, temp.b, shadow.r;\n" - "MUL temp.r, temp.r, value.r;\n" - "MUL temp.g, temp.g, value.r;\n" - "MUL temp.b, temp.b, value.r;\n" - /* for now this just replace smoke shading if rendering fire */ - "CMP result.color, render.r, temp, spec;\n" - "END\n"; - - GLuint prog; - - + GPUProgram *smoke_program; + int progtype = (sds->active_fields & SM_ACTIVE_COLORS) ? GPU_PROGRAM_SMOKE_COLORED : GPU_PROGRAM_SMOKE; float size[3]; if (!tex) { @@ -349,24 +281,17 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, // printf("i: %d\n", i); // printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]); - if (GL_TRUE == glewIsSupported("GL_ARB_fragment_program")) { - glEnable(GL_FRAGMENT_PROGRAM_ARB); - glGenProgramsARB(1, &prog); - - glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog); - /* set shader */ - if (sds->active_fields & SM_ACTIVE_COLORS) - glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_color), shader_color); - else - glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_basic), shader_basic); + smoke_program = GPU_shader_get_builtin_program(progtype); + if (smoke_program) { + GPU_program_bind(smoke_program); /* cell spacing */ - glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, dx, dx, dx, 1.0); + GPU_program_parameter_4f(smoke_program, 0, dx, dx, dx, 1.0); /* custom parameter for smoke style (higher = thicker) */ if (sds->active_fields & SM_ACTIVE_COLORS) - glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 1.0, 1.0, 1.0, 10.0); + GPU_program_parameter_4f(smoke_program, 1, 1.0, 1.0, 1.0, 10.0); else - glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0); + GPU_program_parameter_4f(smoke_program, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0); } else printf("Your gfx card does not support 3D View smoke drawing.\n"); @@ -446,7 +371,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, else glBlendFunc(GL_SRC_ALPHA, GL_ONE); - glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, 1.0, 0.0, 0.0, 0.0); + GPU_program_parameter_4f(smoke_program, 2, 1.0, 0.0, 0.0, 0.0); glBegin(GL_POLYGON); glColor3f(1.0, 1.0, 1.0); for (i = 0; i < numpoints; i++) { @@ -466,7 +391,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, -1.0, 0.0, 0.0, 0.0); + GPU_program_parameter_4f(smoke_program, 2, -1.0, 0.0, 0.0, 0.0); glBegin(GL_POLYGON); glColor3f(1.0, 1.0, 1.0); for (i = 0; i < numpoints; i++) { @@ -499,10 +424,8 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, free(spec_data); free(spec_pixels); - if (GLEW_ARB_fragment_program) { - glDisable(GL_FRAGMENT_PROGRAM_ARB); - glDeleteProgramsARB(1, &prog); - } + if (smoke_program) + GPU_program_unbind(smoke_program); MEM_freeN(points); 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 |