diff options
-rw-r--r-- | intern/cycles/blender/addon/ui.py | 5 | ||||
-rw-r--r-- | release/scripts/startup/bl_ui/properties_data_camera.py | 3 | ||||
-rw-r--r-- | source/blender/gpu/CMakeLists.txt | 6 | ||||
-rw-r--r-- | source/blender/gpu/GPU_compositing.h | 9 | ||||
-rw-r--r-- | source/blender/gpu/GPU_extensions.h | 13 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_codegen.c | 2 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_compositing.c | 763 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_extensions.c | 167 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_simple_shader.c | 1 | ||||
-rw-r--r-- | source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl | 166 | ||||
-rw-r--r-- | source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl | 50 | ||||
-rw-r--r-- | source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl | 58 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_gpu_types.h | 2 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_scene.c | 24 |
14 files changed, 981 insertions, 288 deletions
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 63518d7fdb6..b0337a69e7d 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -457,7 +457,10 @@ class CyclesCamera_PT_dof(CyclesButtonsPanel, Panel): sub.active = cam.dof_object is None sub.prop(cam, "dof_distance", text="Distance") col.prop(dof_options, "fstop") - + col.prop(dof_options, "high_quality") + if dof_options.high_quality: + col.prop(dof_options, "num_blades") + col = split.column() col.label("Aperture:") diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py index 106e31ea89a..2097e82f992 100644 --- a/release/scripts/startup/bl_ui/properties_data_camera.py +++ b/release/scripts/startup/bl_ui/properties_data_camera.py @@ -187,6 +187,9 @@ class DATA_PT_camera_dof(CameraButtonsPanel, Panel): col = split.column() col.prop(dof_options, "fstop") + col.prop(dof_options, "high_quality") + if dof_options.high_quality: + col.prop(dof_options, "num_blades") sub = col.column() sub.active = cam.dof_object is None sub.prop(cam, "dof_distance", text="Distance") diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index b5d9028a8ae..97b0e7e1e0e 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -61,6 +61,9 @@ set(SRC shaders/gpu_shader_fx_ssao_frag.glsl shaders/gpu_shader_fx_dof_frag.glsl shaders/gpu_shader_fx_dof_vert.glsl + shaders/gpu_shader_fx_dof_hq_frag.glsl + shaders/gpu_shader_fx_dof_hq_vert.glsl + shaders/gpu_shader_fx_dof_hq_geo.glsl shaders/gpu_shader_fx_vert.glsl shaders/gpu_shader_material.glsl shaders/gpu_shader_sep_gaussian_blur_frag.glsl @@ -99,6 +102,9 @@ data_to_c_simple(shaders/gpu_shader_fx_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_fx_ssao_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_fx_dof_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_fx_dof_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_fx_dof_hq_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_fx_dof_hq_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_fx_dof_hq_geo.glsl SRC) data_to_c_simple(shaders/gpu_shader_fx_depth_resolve.glsl SRC) data_to_c_simple(shaders/gpu_shader_fx_lib.glsl SRC) diff --git a/source/blender/gpu/GPU_compositing.h b/source/blender/gpu/GPU_compositing.h index 93f1bc64922..5589084705b 100644 --- a/source/blender/gpu/GPU_compositing.h +++ b/source/blender/gpu/GPU_compositing.h @@ -61,11 +61,16 @@ typedef enum GPUFXShaderEffect { GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR = 5, GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE = 6, - GPU_SHADER_FX_DEPTH_RESOLVE = 7, + /* high quality */ + GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE = 7, + GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO = 8, + GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE = 9, + + GPU_SHADER_FX_DEPTH_RESOLVE = 10, } GPUFXShaderEffect; /* keep in synch with enum above! */ -#define MAX_FX_SHADERS 8 +#define MAX_FX_SHADERS 11 /* generate a new FX compositor */ GPUFX *GPU_fx_compositor_create(void); diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index 985cebc8687..aed1a88938a 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -61,13 +61,14 @@ bool GPU_non_power_of_two_support(void); bool GPU_vertex_buffer_support(void); bool GPU_display_list_support(void); bool GPU_bicubic_bump_support(void); +bool GPU_geometry_shader_support(void); +bool GPU_instanced_drawing_support(void); int GPU_max_texture_size(void); int GPU_color_depth(void); void GPU_code_generate_glsl_lib(void); - /* GPU Types */ typedef enum GPUDeviceType { @@ -120,7 +121,7 @@ GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, GPUHDRType GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels); GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]); GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]); -GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]); GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]); GPUTexture *GPU_texture_from_blender(struct Image *ima, struct ImageUser *iuser, bool is_data, double time, int mipmap); @@ -136,7 +137,7 @@ void GPU_texture_ref(GPUTexture *tex); void GPU_texture_bind(GPUTexture *tex, int number); void GPU_texture_unbind(GPUTexture *tex); -void GPU_depth_texture_mode(GPUTexture *tex, bool compare, bool use_filter); +void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter); GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex); @@ -183,7 +184,7 @@ int GPU_offscreen_height(const GPUOffScreen *ofs); * - only for fragment shaders now * - must call texture bind before setting a texture as uniform! */ -GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *libcode, const char *defines); +GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines); void GPU_shader_free(GPUShader *shader); void GPU_shader_bind(GPUShader *shader); @@ -192,8 +193,12 @@ void GPU_shader_unbind(void); int GPU_shader_get_uniform(GPUShader *shader, const char *name); void GPU_shader_uniform_vector(GPUShader *shader, int location, int length, int arraysize, const float *value); +void GPU_shader_uniform_vector_int(GPUShader *shader, int location, int length, + int arraysize, const int *value); + void GPU_shader_uniform_texture(GPUShader *shader, int location, GPUTexture *tex); void GPU_shader_uniform_int(GPUShader *shader, int location, int value); +void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number); int GPU_shader_get_attribute(GPUShader *shader, const char *name); diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 40c9ec0d862..fcfb68d4629 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -1419,7 +1419,7 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, /* generate code and compile with opengl */ fragmentcode = code_generate_fragment(nodes, outlink->output); vertexcode = code_generate_vertex(nodes, type); - shader = GPU_shader_create(vertexcode, fragmentcode, glsl_material_library, NULL); + shader = GPU_shader_create(vertexcode, fragmentcode, NULL, glsl_material_library, NULL); /* failed? */ if (!shader) { diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c index 511167b775a..bfa938d0fed 100644 --- a/source/blender/gpu/intern/gpu_compositing.c +++ b/source/blender/gpu/intern/gpu_compositing.c @@ -62,11 +62,20 @@ struct GPUFX { * depth/color framebuffer. Could be extended later though */ GPUFrameBuffer *gbuffer; + /* dimensions of the gbuffer */ + int gbuffer_dim[2]; + /* texture bound to the first color attachment of the gbuffer */ GPUTexture *color_buffer; /* second texture used for ping-pong compositing */ GPUTexture *color_buffer_sec; + /* texture bound to the depth attachment of the gbuffer */ + GPUTexture *depth_buffer; + GPUTexture *depth_buffer_xray; + + /* texture used for jittering for various effects */ + GPUTexture *jitter_buffer; /* all those buffers below have to coexist. Fortunately they are all quarter sized (1/16th of memory) of original framebuffer */ int dof_downsampled_w; @@ -80,26 +89,20 @@ struct GPUFX { GPUTexture *dof_near_coc_final_buffer; /* half size blur buffer */ - GPUTexture *dof_half_downsampled; - /* high quality dof texture downsamplers. 6 levels means 64 pixels wide */ - GPUTexture *dof_nearfar_coc[6]; + GPUTexture *dof_half_downsampled_near; + GPUTexture *dof_half_downsampled_far; + /* high quality dof texture downsamplers. 6 levels means 64 pixels wide - should be enough */ + GPUTexture *dof_nearfar_coc; GPUTexture *dof_near_blur; GPUTexture *dof_far_blur; - GPUTexture *dof_concentric_samples_tex; - - /* texture bound to the depth attachment of the gbuffer */ - GPUTexture *depth_buffer; - GPUTexture *depth_buffer_xray; - /* texture used for jittering for various effects */ - GPUTexture *jitter_buffer; + /* for high quality we use again a spiral texture with radius adapted */ + bool dof_high_quality; /* texture used for ssao */ - int ssao_sample_count; - GPUTexture *ssao_concentric_samples_tex; + int ssao_sample_count_cache; + GPUTexture *ssao_spiral_samples_tex; - /* dimensions of the gbuffer */ - int gbuffer_dim[2]; GPUFXSettings settings; @@ -192,16 +195,17 @@ static void cleanup_fx_dof_buffers(GPUFX *fx) fx->dof_near_coc_final_buffer = NULL; } - if (fx->dof_half_downsampled) { - GPU_texture_free(fx->dof_half_downsampled); - fx->dof_half_downsampled = NULL; + if (fx->dof_half_downsampled_near) { + GPU_texture_free(fx->dof_half_downsampled_near); + fx->dof_half_downsampled_near = NULL; } - if (fx->dof_nearfar_coc[0]) { - int i; - for (i = 0; i < 6; i++) { - GPU_texture_free(fx->dof_nearfar_coc[i]); - fx->dof_nearfar_coc[i] = NULL; - } + if (fx->dof_half_downsampled_far) { + GPU_texture_free(fx->dof_half_downsampled_far); + fx->dof_half_downsampled_far = NULL; + } + if (fx->dof_nearfar_coc) { + GPU_texture_free(fx->dof_nearfar_coc); + fx->dof_nearfar_coc = NULL; } if (fx->dof_near_blur) { GPU_texture_free(fx->dof_near_blur); @@ -211,10 +215,6 @@ static void cleanup_fx_dof_buffers(GPUFX *fx) GPU_texture_free(fx->dof_far_blur); fx->dof_far_blur = NULL; } - if (fx->dof_concentric_samples_tex) { - GPU_texture_free(fx->dof_concentric_samples_tex); - fx->dof_concentric_samples_tex = NULL; - } } static void cleanup_fx_gl_data(GPUFX *fx, bool do_fbo) @@ -245,9 +245,9 @@ static void cleanup_fx_gl_data(GPUFX *fx, bool do_fbo) cleanup_fx_dof_buffers(fx); - if (fx->ssao_concentric_samples_tex) { - GPU_texture_free(fx->ssao_concentric_samples_tex); - fx->ssao_concentric_samples_tex = NULL; + if (fx->ssao_spiral_samples_tex) { + GPU_texture_free(fx->ssao_spiral_samples_tex); + fx->ssao_spiral_samples_tex = NULL; } if (fx->jitter_buffer && do_fbo) { @@ -279,7 +279,7 @@ static GPUTexture * create_jitter_texture(void) normalize_v2(jitter[i]); } - return GPU_texture_create_2D_procedural(64, 64, &jitter[0][0], NULL); + return GPU_texture_create_2D_procedural(64, 64, &jitter[0][0], true, NULL); } @@ -356,54 +356,108 @@ bool GPU_fx_compositor_initialize_passes( } if (fx_flag & GPU_FX_FLAG_SSAO) { - if (fx_settings->ssao->samples != fx->ssao_sample_count || !fx->ssao_concentric_samples_tex) { + if (fx_settings->ssao->samples != fx->ssao_sample_count_cache || !fx->ssao_spiral_samples_tex) { if (fx_settings->ssao->samples < 1) fx_settings->ssao->samples = 1; - fx->ssao_sample_count = fx_settings->ssao->samples; + fx->ssao_sample_count_cache = fx_settings->ssao->samples; - if (fx->ssao_concentric_samples_tex) { - GPU_texture_free(fx->ssao_concentric_samples_tex); + if (fx->ssao_spiral_samples_tex) { + GPU_texture_free(fx->ssao_spiral_samples_tex); } - fx->ssao_concentric_samples_tex = create_spiral_sample_texture(fx_settings->ssao->samples); + fx->ssao_spiral_samples_tex = create_spiral_sample_texture(fx_settings->ssao->samples); } } else { - if (fx->ssao_concentric_samples_tex) { - GPU_texture_free(fx->ssao_concentric_samples_tex); - fx->ssao_concentric_samples_tex = NULL; + if (fx->ssao_spiral_samples_tex) { + GPU_texture_free(fx->ssao_spiral_samples_tex); + fx->ssao_spiral_samples_tex = NULL; } } /* create textures for dof effect */ if (fx_flag & GPU_FX_FLAG_DOF) { - if (!fx->dof_near_coc_buffer || !fx->dof_near_coc_blurred_buffer || !fx->dof_near_coc_final_buffer) { + bool dof_high_quality = (fx_settings->dof->high_quality != 0); + + if (dof_high_quality) { + fx->dof_downsampled_w = w / 2; + fx->dof_downsampled_h = h / 2; + + if (!fx->dof_half_downsampled_near || !fx->dof_nearfar_coc || !fx->dof_near_blur || + !fx->dof_far_blur || !fx->dof_half_downsampled_far) { + + if (!(fx->dof_half_downsampled_near = GPU_texture_create_2D( + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + if (!(fx->dof_half_downsampled_far = GPU_texture_create_2D( + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_procedural( + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, false, err_out))) + { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + + + if (!(fx->dof_near_blur = GPU_texture_create_2D( + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out))) + { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + + if (!(fx->dof_far_blur = GPU_texture_create_2D( + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out))) + { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + } + } + else { fx->dof_downsampled_w = w / 4; fx->dof_downsampled_h = h / 4; - if (!(fx->dof_near_coc_buffer = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) - { - printf("%.256s\n", err_out); - cleanup_fx_gl_data(fx, true); - return false; - } - if (!(fx->dof_near_coc_blurred_buffer = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) - { - printf("%.256s\n", err_out); - cleanup_fx_gl_data(fx, true); - return false; - } - if (!(fx->dof_near_coc_final_buffer = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) - { - printf("%.256s\n", err_out); - cleanup_fx_gl_data(fx, true); - return false; + if (!fx->dof_near_coc_buffer || !fx->dof_near_coc_blurred_buffer || !fx->dof_near_coc_final_buffer) { + + if (!(fx->dof_near_coc_buffer = GPU_texture_create_2D( + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + if (!(fx->dof_near_coc_blurred_buffer = GPU_texture_create_2D( + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + if (!(fx->dof_near_coc_final_buffer = GPU_texture_create_2D( + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } } } + + fx->dof_high_quality = dof_high_quality; } else { /* cleanup unnecessary buffers */ @@ -544,14 +598,14 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx) GPU_shader_bind(depth_resolve_shader); GPU_texture_bind(fx->depth_buffer_xray, 0); - GPU_depth_texture_mode(fx->depth_buffer_xray, false, true); + GPU_texture_filter_mode(fx->depth_buffer_xray, false, true); GPU_shader_uniform_texture(depth_resolve_shader, depth_uniform, fx->depth_buffer_xray); /* draw */ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* disable bindings */ - GPU_depth_texture_mode(fx->depth_buffer_xray, true, false); + GPU_texture_filter_mode(fx->depth_buffer_xray, true, false); GPU_texture_unbind(fx->depth_buffer_xray); GPU_shader_unbind(); @@ -643,7 +697,7 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, fx_ssao->attenuation, 0.0f}; float sample_params[4]; - sample_params[0] = fx->ssao_sample_count; + sample_params[0] = fx->ssao_sample_count_cache; /* multiplier so we tile the random texture on screen */ sample_params[2] = fx->gbuffer_dim[0] / 64.0; sample_params[3] = fx->gbuffer_dim[1] / 64.0; @@ -668,14 +722,14 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str GPU_shader_uniform_texture(ssao_shader, color_uniform, src); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_depth_texture_mode(fx->depth_buffer, false, true); + GPU_texture_filter_mode(fx->depth_buffer, false, true); GPU_shader_uniform_texture(ssao_shader, depth_uniform, fx->depth_buffer); GPU_texture_bind(fx->jitter_buffer, numslots++); GPU_shader_uniform_texture(ssao_shader, ssao_jitter_uniform, fx->jitter_buffer); - GPU_texture_bind(fx->ssao_concentric_samples_tex, numslots++); - GPU_shader_uniform_texture(ssao_shader, ssao_concentric_tex, fx->ssao_concentric_samples_tex); + GPU_texture_bind(fx->ssao_spiral_samples_tex, numslots++); + GPU_shader_uniform_texture(ssao_shader, ssao_concentric_tex, fx->ssao_spiral_samples_tex); /* draw */ gpu_fx_bind_render_target(&passes_left, fx, ofs, target); @@ -684,10 +738,10 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str /* disable bindings */ GPU_texture_unbind(src); - GPU_depth_texture_mode(fx->depth_buffer, true, false); + GPU_texture_filter_mode(fx->depth_buffer, true, false); GPU_texture_unbind(fx->depth_buffer); GPU_texture_unbind(fx->jitter_buffer); - GPU_texture_unbind(fx->ssao_concentric_samples_tex); + GPU_texture_unbind(fx->ssao_spiral_samples_tex); /* may not be attached, in that case this just returns */ if (target) { @@ -709,7 +763,6 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str /* second pass, dof */ if (fx->effects & GPU_FX_FLAG_DOF) { const GPUDOFSettings *fx_dof = fx->settings.dof; - GPUShader *dof_shader_pass1, *dof_shader_pass2, *dof_shader_pass3, *dof_shader_pass4, *dof_shader_pass5; float dof_params[4]; float scale = scene->unit.system ? scene->unit.scale_length : 1.0f; /* this is factor that converts to the scene scale. focal length and sensor are expressed in mm @@ -722,243 +775,456 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str dof_params[0] = aperture * fabsf(scale_camera * fx_dof->focal_length / ((fx_dof->focus_distance / scale) - scale_camera * fx_dof->focal_length)); dof_params[1] = fx_dof->focus_distance / scale; dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor); - dof_params[3] = 0.0f; - - /* DOF effect has many passes but most of them are performed on a texture whose dimensions are 4 times less than the original - * (16 times lower than original screen resolution). Technique used is not very exact but should be fast enough and is based - * on "Practical Post-Process Depth of Field" see http://http.developer.nvidia.com/GPUGems3/gpugems3_ch28.html */ - dof_shader_pass1 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE, is_persp); - dof_shader_pass2 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO, is_persp); - dof_shader_pass3 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE, is_persp); - dof_shader_pass4 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR, is_persp); - dof_shader_pass5 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE, is_persp); - - /* error occured, restore framebuffers and return */ - if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3 && dof_shader_pass4 && dof_shader_pass5)) { - GPU_framebuffer_texture_unbind(fx->gbuffer, NULL); - GPU_framebuffer_restore(); - return false; - } + dof_params[3] = fx_dof->num_blades; - /* pass first, first level of blur in low res buffer */ - { - int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform; - int viewvecs_uniform; + if (fx->dof_high_quality) { + GPUShader *dof_shader_pass1, *dof_shader_pass2, *dof_shader_pass3; - float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]}; + /* custom shaders close to the effect described in CryEngine 3 Graphics Gems */ + dof_shader_pass1 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE, is_persp); + dof_shader_pass2 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO, is_persp); + dof_shader_pass3 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE, is_persp); - dof_uniform = GPU_shader_get_uniform(dof_shader_pass1, "dof_params"); - invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim"); - color_uniform = GPU_shader_get_uniform(dof_shader_pass1, "colorbuffer"); - depth_uniform = GPU_shader_get_uniform(dof_shader_pass1, "depthbuffer"); - viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass1, "viewvecs"); + /* error occured, restore framebuffers and return */ + if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3)) { + GPU_framebuffer_texture_unbind(fx->gbuffer, NULL); + GPU_framebuffer_restore(); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); - GPU_shader_bind(dof_shader_pass1); + GPU_shader_unbind(); + return false; + } - GPU_shader_uniform_vector(dof_shader_pass1, dof_uniform, 4, 1, dof_params); - GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim); - GPU_shader_uniform_vector(dof_shader_pass1, viewvecs_uniform, 4, 3, viewvecs[0]); + /* pass first, downsample the color buffer to near/far targets and calculate coc texture */ + { + int depth_uniform, dof_uniform; + int viewvecs_uniform; + int invrendertargetdim_uniform, color_uniform; + + float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h}; + + invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim"); + color_uniform = GPU_shader_get_uniform(dof_shader_pass1, "colorbuffer"); + dof_uniform = GPU_shader_get_uniform(dof_shader_pass1, "dof_params"); + invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim"); + depth_uniform = GPU_shader_get_uniform(dof_shader_pass1, "depthbuffer"); + viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass1, "viewvecs"); + + GPU_shader_bind(dof_shader_pass1); + + GPU_shader_uniform_vector(dof_shader_pass1, dof_uniform, 4, 1, dof_params); + GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim); + GPU_shader_uniform_vector(dof_shader_pass1, viewvecs_uniform, 4, 3, viewvecs[0]); + + GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim); + + GPU_texture_bind(fx->depth_buffer, numslots++); + GPU_texture_filter_mode(fx->depth_buffer, false, false); + GPU_shader_uniform_texture(dof_shader_pass1, depth_uniform, fx->depth_buffer); + + GPU_texture_bind(src, numslots++); + /* disable filtering for the texture so custom downsample can do the right thing */ + GPU_texture_filter_mode(src, false, false); + GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, src); + + /* target is the downsampled coc buffer */ + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_near, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_far, 1, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_nearfar_coc, 2, NULL); + /* binding takes care of setting the viewport to the downsampled size */ + GPU_framebuffer_slots_bind(fx->gbuffer, 0); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + /* disable bindings */ + GPU_texture_filter_mode(src, false, true); + GPU_texture_unbind(src); + GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_unbind(fx->depth_buffer); + + GPU_framebuffer_texture_detach(fx->dof_half_downsampled_near); + GPU_framebuffer_texture_detach(fx->dof_half_downsampled_far); + GPU_framebuffer_texture_detach(fx->dof_nearfar_coc); + GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_half_downsampled_near); + + numslots = 0; + } - GPU_texture_bind(src, numslots++); - GPU_shader_uniform_texture(dof_shader_pass1, color_uniform, src); + /* second pass, shoot quads for every pixel in the downsampled buffers, scaling according + * to circle of confusion */ + { + int rendertargetdim_uniform, coc_uniform, color_uniform, select_uniform, dof_uniform; + int rendertargetdim[2] = {fx->dof_downsampled_w, fx->dof_downsampled_h}; + float selection[2] = {0.0f, 1.0f}; - GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_depth_texture_mode(fx->depth_buffer, false, true); - GPU_shader_uniform_texture(dof_shader_pass1, depth_uniform, fx->depth_buffer); + rendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass2, "rendertargetdim"); - /* target is the downsampled coc buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL); - /* binding takes care of setting the viewport to the downsampled size */ - GPU_texture_bind_as_framebuffer(fx->dof_near_coc_buffer); + color_uniform = GPU_shader_get_uniform(dof_shader_pass2, "colorbuffer"); + coc_uniform = GPU_shader_get_uniform(dof_shader_pass2, "cocbuffer"); + select_uniform = GPU_shader_get_uniform(dof_shader_pass2, "layerselection"); + dof_uniform = GPU_shader_get_uniform(dof_shader_pass1, "dof_params"); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - /* disable bindings */ - GPU_texture_unbind(src); - GPU_depth_texture_mode(fx->depth_buffer, true, false); - GPU_texture_unbind(fx->depth_buffer); + GPU_shader_bind(dof_shader_pass2); - GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer); - numslots = 0; + GPU_shader_uniform_vector(dof_shader_pass2, dof_uniform, 4, 1, dof_params); + GPU_shader_uniform_vector_int(dof_shader_pass2, rendertargetdim_uniform, 2, 1, rendertargetdim); + GPU_shader_uniform_vector(dof_shader_pass2, select_uniform, 2, 1, selection); + + GPU_texture_bind(fx->dof_nearfar_coc, numslots++); + GPU_shader_uniform_texture(dof_shader_pass2, coc_uniform, fx->dof_nearfar_coc); + + GPU_texture_bind(fx->dof_half_downsampled_far, numslots++); + GPU_texture_bind(fx->dof_half_downsampled_near, numslots++); + GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_half_downsampled_far); + GPU_texture_filter_mode(fx->dof_half_downsampled_far, false, false); + + /* target is the downsampled coc buffer */ + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0, NULL); + GPU_texture_bind_as_framebuffer(fx->dof_far_blur); + + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE); + /* have to clear the buffer unfortunately */ + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */ + glDrawArraysInstancedEXT(GL_POINTS, 0, 1, fx->dof_downsampled_w * fx->dof_downsampled_h); + + GPU_texture_unbind(fx->dof_half_downsampled_far); + GPU_framebuffer_texture_detach(fx->dof_far_blur); + + GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_half_downsampled_near); + GPU_texture_filter_mode(fx->dof_half_downsampled_near, false, false); + + selection[0] = 1.0f; + selection[1] = 0.0f; + + GPU_shader_uniform_vector(dof_shader_pass2, select_uniform, 2, 1, selection); + + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0, NULL); + /* have to clear the buffer unfortunately */ + glClear(GL_COLOR_BUFFER_BIT); + /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */ + glDrawArraysInstancedEXT(GL_POINTS, 0, 1, fx->dof_downsampled_w * fx->dof_downsampled_h); + + /* disable bindings */ + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_BLEND); + + GPU_framebuffer_texture_detach(fx->dof_near_blur); + + GPU_texture_unbind(fx->dof_half_downsampled_near); + GPU_texture_unbind(fx->dof_nearfar_coc); + + GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_far_blur); + } + + /* third pass, accumulate the near/far blur fields */ + { + int invrendertargetdim_uniform, near_uniform, color_uniform; + int dof_uniform, far_uniform, viewvecs_uniform, depth_uniform; + + float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h}; + + dof_uniform = GPU_shader_get_uniform(dof_shader_pass3, "dof_params"); + invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass3, "invrendertargetdim"); + color_uniform = GPU_shader_get_uniform(dof_shader_pass3, "colorbuffer"); + far_uniform = GPU_shader_get_uniform(dof_shader_pass3, "farbuffer"); + near_uniform = GPU_shader_get_uniform(dof_shader_pass3, "nearbuffer"); + viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass1, "viewvecs"); + depth_uniform = GPU_shader_get_uniform(dof_shader_pass1, "depthbuffer"); + + GPU_shader_bind(dof_shader_pass3); + + GPU_shader_uniform_vector(dof_shader_pass3, dof_uniform, 4, 1, dof_params); + + GPU_shader_uniform_vector(dof_shader_pass3, invrendertargetdim_uniform, 2, 1, invrendertargetdim); + GPU_shader_uniform_vector(dof_shader_pass3, viewvecs_uniform, 4, 3, viewvecs[0]); + + GPU_texture_bind(fx->dof_near_blur, numslots++); + GPU_shader_uniform_texture(dof_shader_pass3, near_uniform, fx->dof_near_blur); + GPU_texture_filter_mode(fx->dof_near_blur, false, false); + + GPU_texture_bind(fx->dof_far_blur, numslots++); + GPU_shader_uniform_texture(dof_shader_pass3, far_uniform, fx->dof_far_blur); + GPU_texture_filter_mode(fx->dof_far_blur, false, false); + + GPU_texture_bind(fx->depth_buffer, numslots++); + GPU_texture_filter_mode(fx->depth_buffer, false, false); + GPU_shader_uniform_texture(dof_shader_pass1, depth_uniform, fx->depth_buffer); + + GPU_texture_bind(src, numslots++); + GPU_shader_uniform_texture(dof_shader_pass3, color_uniform, src); + + /* if this is the last pass, prepare for rendering on the frambuffer */ + gpu_fx_bind_render_target(&passes_left, fx, ofs, target); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + /* disable bindings */ + GPU_texture_unbind(fx->dof_near_blur); + GPU_texture_unbind(fx->dof_far_blur); + GPU_texture_unbind(src); + GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_unbind(fx->depth_buffer); + + /* may not be attached, in that case this just returns */ + if (target) { + GPU_framebuffer_texture_detach(target); + if (ofs) { + GPU_offscreen_bind(ofs, false); + } + else { + GPU_framebuffer_restore(); + } + } + + numslots = 0; + } } + else { + GPUShader *dof_shader_pass1, *dof_shader_pass2, *dof_shader_pass3, *dof_shader_pass4, *dof_shader_pass5; + + /* DOF effect has many passes but most of them are performed on a texture whose dimensions are 4 times less than the original + * (16 times lower than original screen resolution). Technique used is not very exact but should be fast enough and is based + * on "Practical Post-Process Depth of Field" see http://http.developer.nvidia.com/GPUGems3/gpugems3_ch28.html */ + dof_shader_pass1 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE, is_persp); + dof_shader_pass2 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO, is_persp); + dof_shader_pass3 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE, is_persp); + dof_shader_pass4 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR, is_persp); + dof_shader_pass5 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE, is_persp); + + /* error occured, restore framebuffers and return */ + if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3 && dof_shader_pass4 && dof_shader_pass5)) { + GPU_framebuffer_texture_unbind(fx->gbuffer, NULL); + GPU_framebuffer_restore(); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + GPU_shader_unbind(); + return false; + } - /* second pass, gaussian blur the downsampled image */ - { - int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform; - int viewvecs_uniform; - float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer), - 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)}; - float tmp = invrendertargetdim[0]; - invrendertargetdim[0] = 0.0f; + /* pass first, first level of blur in low res buffer */ + { + int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform; + int viewvecs_uniform; - dof_params[2] = GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer) / (scale_camera * fx_dof->sensor); + float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]}; - dof_uniform = GPU_shader_get_uniform(dof_shader_pass2, "dof_params"); - invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass2, "invrendertargetdim"); - color_uniform = GPU_shader_get_uniform(dof_shader_pass2, "colorbuffer"); - depth_uniform = GPU_shader_get_uniform(dof_shader_pass2, "depthbuffer"); - viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass2, "viewvecs"); + dof_uniform = GPU_shader_get_uniform(dof_shader_pass1, "dof_params"); + invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim"); + color_uniform = GPU_shader_get_uniform(dof_shader_pass1, "colorbuffer"); + depth_uniform = GPU_shader_get_uniform(dof_shader_pass1, "depthbuffer"); + viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass1, "viewvecs"); - /* Blurring vertically */ - GPU_shader_bind(dof_shader_pass2); + GPU_shader_bind(dof_shader_pass1); - GPU_shader_uniform_vector(dof_shader_pass2, dof_uniform, 4, 1, dof_params); - GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim); - GPU_shader_uniform_vector(dof_shader_pass2, viewvecs_uniform, 4, 3, viewvecs[0]); + GPU_shader_uniform_vector(dof_shader_pass1, dof_uniform, 4, 1, dof_params); + GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim); + GPU_shader_uniform_vector(dof_shader_pass1, viewvecs_uniform, 4, 3, viewvecs[0]); - GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_depth_texture_mode(fx->depth_buffer, false, true); - GPU_shader_uniform_texture(dof_shader_pass2, depth_uniform, fx->depth_buffer); + GPU_texture_bind(src, numslots++); + GPU_shader_uniform_texture(dof_shader_pass1, color_uniform, src); - GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); - GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_buffer); + GPU_texture_bind(fx->depth_buffer, numslots++); + GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_shader_uniform_texture(dof_shader_pass1, depth_uniform, fx->depth_buffer); - /* use final buffer as a temp here */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL); + /* target is the downsampled coc buffer */ + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL); + /* binding takes care of setting the viewport to the downsampled size */ + GPU_texture_bind_as_framebuffer(fx->dof_near_coc_buffer); - /* Drawing quad */ - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + /* disable bindings */ + GPU_texture_unbind(src); + GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_unbind(fx->depth_buffer); - /* *unbind/detach */ - GPU_texture_unbind(fx->dof_near_coc_buffer); - GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer); + GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer); + numslots = 0; + } - /* Blurring horizontally */ - invrendertargetdim[0] = tmp; - invrendertargetdim[1] = 0.0f; - GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim); + /* second pass, gaussian blur the downsampled image */ + { + int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform; + int viewvecs_uniform; + float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer), + 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)}; + float tmp = invrendertargetdim[0]; + invrendertargetdim[0] = 0.0f; - GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++); - GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_final_buffer); + dof_params[2] = GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer) / (scale_camera * fx_dof->sensor); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0, NULL); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + dof_uniform = GPU_shader_get_uniform(dof_shader_pass2, "dof_params"); + invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass2, "invrendertargetdim"); + color_uniform = GPU_shader_get_uniform(dof_shader_pass2, "colorbuffer"); + depth_uniform = GPU_shader_get_uniform(dof_shader_pass2, "depthbuffer"); + viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass2, "viewvecs"); - /* *unbind/detach */ - GPU_depth_texture_mode(fx->depth_buffer, true, false); - GPU_texture_unbind(fx->depth_buffer); + /* Blurring vertically */ + GPU_shader_bind(dof_shader_pass2); - GPU_texture_unbind(fx->dof_near_coc_final_buffer); - GPU_framebuffer_texture_detach(fx->dof_near_coc_blurred_buffer); + GPU_shader_uniform_vector(dof_shader_pass2, dof_uniform, 4, 1, dof_params); + GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim); + GPU_shader_uniform_vector(dof_shader_pass2, viewvecs_uniform, 4, 3, viewvecs[0]); - dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor); + GPU_texture_bind(fx->depth_buffer, numslots++); + GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_shader_uniform_texture(dof_shader_pass2, depth_uniform, fx->depth_buffer); - numslots = 0; - } + GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); + GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_buffer); - /* third pass, calculate near coc */ - { - int near_coc_downsampled, near_coc_blurred; + /* use final buffer as a temp here */ + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL); - near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass3, "colorbuffer"); - near_coc_blurred = GPU_shader_get_uniform(dof_shader_pass3, "blurredcolorbuffer"); + /* Drawing quad */ + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - GPU_shader_bind(dof_shader_pass3); + /* *unbind/detach */ + GPU_texture_unbind(fx->dof_near_coc_buffer); + GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer); - GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); - GPU_shader_uniform_texture(dof_shader_pass3, near_coc_downsampled, fx->dof_near_coc_buffer); + /* Blurring horizontally */ + invrendertargetdim[0] = tmp; + invrendertargetdim[1] = 0.0f; + GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim); - GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++); - GPU_shader_uniform_texture(dof_shader_pass3, near_coc_blurred, fx->dof_near_coc_blurred_buffer); + GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++); + GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_final_buffer); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0, NULL); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - /* disable bindings */ - GPU_texture_unbind(fx->dof_near_coc_buffer); - GPU_texture_unbind(fx->dof_near_coc_blurred_buffer); + /* *unbind/detach */ + GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_unbind(fx->depth_buffer); - /* unbinding here restores the size to the original */ - GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer); + GPU_texture_unbind(fx->dof_near_coc_final_buffer); + GPU_framebuffer_texture_detach(fx->dof_near_coc_blurred_buffer); - numslots = 0; - } + dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor); - /* fourth pass blur final coc once to eliminate discontinuities */ - { - int near_coc_downsampled; - int invrendertargetdim_uniform; - float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer), - 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)}; + numslots = 0; + } - near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass4, "colorbuffer"); - invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass4, "invrendertargetdim"); + /* third pass, calculate near coc */ + { + int near_coc_downsampled, near_coc_blurred; - GPU_shader_bind(dof_shader_pass4); + near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass3, "colorbuffer"); + near_coc_blurred = GPU_shader_get_uniform(dof_shader_pass3, "blurredcolorbuffer"); - GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++); - GPU_shader_uniform_texture(dof_shader_pass4, near_coc_downsampled, fx->dof_near_coc_final_buffer); - GPU_shader_uniform_vector(dof_shader_pass4, invrendertargetdim_uniform, 2, 1, invrendertargetdim); + GPU_shader_bind(dof_shader_pass3); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL); + GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); + GPU_shader_uniform_texture(dof_shader_pass3, near_coc_downsampled, fx->dof_near_coc_buffer); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - /* disable bindings */ - GPU_texture_unbind(fx->dof_near_coc_final_buffer); + GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++); + GPU_shader_uniform_texture(dof_shader_pass3, near_coc_blurred, fx->dof_near_coc_blurred_buffer); - /* unbinding here restores the size to the original */ - GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_near_coc_buffer); - GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL); - numslots = 0; - } + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + /* disable bindings */ + GPU_texture_unbind(fx->dof_near_coc_buffer); + GPU_texture_unbind(fx->dof_near_coc_blurred_buffer); - /* final pass, merge blurred layers according to final calculated coc */ - { - int medium_blurred_uniform, high_blurred_uniform, original_uniform, depth_uniform, dof_uniform; - int invrendertargetdim_uniform, viewvecs_uniform; - float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]}; + /* unbinding here restores the size to the original */ + GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer); - medium_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "mblurredcolorbuffer"); - high_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "blurredcolorbuffer"); - dof_uniform = GPU_shader_get_uniform(dof_shader_pass5, "dof_params"); - invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass5, "invrendertargetdim"); - original_uniform = GPU_shader_get_uniform(dof_shader_pass5, "colorbuffer"); - depth_uniform = GPU_shader_get_uniform(dof_shader_pass5, "depthbuffer"); - viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass5, "viewvecs"); + numslots = 0; + } - GPU_shader_bind(dof_shader_pass5); + /* fourth pass blur final coc once to eliminate discontinuities */ + { + int near_coc_downsampled; + int invrendertargetdim_uniform; + float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer), + 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)}; - GPU_shader_uniform_vector(dof_shader_pass5, dof_uniform, 4, 1, dof_params); - GPU_shader_uniform_vector(dof_shader_pass5, invrendertargetdim_uniform, 2, 1, invrendertargetdim); - GPU_shader_uniform_vector(dof_shader_pass5, viewvecs_uniform, 4, 3, viewvecs[0]); + near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass4, "colorbuffer"); + invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass4, "invrendertargetdim"); - GPU_texture_bind(src, numslots++); - GPU_shader_uniform_texture(dof_shader_pass5, original_uniform, src); + GPU_shader_bind(dof_shader_pass4); - GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++); - GPU_shader_uniform_texture(dof_shader_pass5, high_blurred_uniform, fx->dof_near_coc_blurred_buffer); + GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++); + GPU_shader_uniform_texture(dof_shader_pass4, near_coc_downsampled, fx->dof_near_coc_final_buffer); + GPU_shader_uniform_vector(dof_shader_pass4, invrendertargetdim_uniform, 2, 1, invrendertargetdim); - GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); - GPU_shader_uniform_texture(dof_shader_pass5, medium_blurred_uniform, fx->dof_near_coc_buffer); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL); - GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_depth_texture_mode(fx->depth_buffer, false, true); - GPU_shader_uniform_texture(dof_shader_pass5, depth_uniform, fx->depth_buffer); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + /* disable bindings */ + GPU_texture_unbind(fx->dof_near_coc_final_buffer); - /* if this is the last pass, prepare for rendering on the frambuffer */ - gpu_fx_bind_render_target(&passes_left, fx, ofs, target); + /* unbinding here restores the size to the original */ + GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_near_coc_buffer); + GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - /* disable bindings */ - GPU_texture_unbind(fx->dof_near_coc_buffer); - GPU_texture_unbind(fx->dof_near_coc_blurred_buffer); - GPU_texture_unbind(src); - GPU_depth_texture_mode(fx->depth_buffer, true, false); - GPU_texture_unbind(fx->depth_buffer); + numslots = 0; + } - /* may not be attached, in that case this just returns */ - if (target) { - GPU_framebuffer_texture_detach(target); - if (ofs) { - GPU_offscreen_bind(ofs, false); - } - else { - GPU_framebuffer_restore(); + /* final pass, merge blurred layers according to final calculated coc */ + { + int medium_blurred_uniform, high_blurred_uniform, original_uniform, depth_uniform, dof_uniform; + int invrendertargetdim_uniform, viewvecs_uniform; + float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]}; + + medium_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "mblurredcolorbuffer"); + high_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "blurredcolorbuffer"); + dof_uniform = GPU_shader_get_uniform(dof_shader_pass5, "dof_params"); + invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass5, "invrendertargetdim"); + original_uniform = GPU_shader_get_uniform(dof_shader_pass5, "colorbuffer"); + depth_uniform = GPU_shader_get_uniform(dof_shader_pass5, "depthbuffer"); + viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass5, "viewvecs"); + + GPU_shader_bind(dof_shader_pass5); + + GPU_shader_uniform_vector(dof_shader_pass5, dof_uniform, 4, 1, dof_params); + GPU_shader_uniform_vector(dof_shader_pass5, invrendertargetdim_uniform, 2, 1, invrendertargetdim); + GPU_shader_uniform_vector(dof_shader_pass5, viewvecs_uniform, 4, 3, viewvecs[0]); + + GPU_texture_bind(src, numslots++); + GPU_shader_uniform_texture(dof_shader_pass5, original_uniform, src); + + GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++); + GPU_shader_uniform_texture(dof_shader_pass5, high_blurred_uniform, fx->dof_near_coc_blurred_buffer); + + GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); + GPU_shader_uniform_texture(dof_shader_pass5, medium_blurred_uniform, fx->dof_near_coc_buffer); + + GPU_texture_bind(fx->depth_buffer, numslots++); + GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_shader_uniform_texture(dof_shader_pass5, depth_uniform, fx->depth_buffer); + + /* if this is the last pass, prepare for rendering on the frambuffer */ + gpu_fx_bind_render_target(&passes_left, fx, ofs, target); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + /* disable bindings */ + GPU_texture_unbind(fx->dof_near_coc_buffer); + GPU_texture_unbind(fx->dof_near_coc_blurred_buffer); + GPU_texture_unbind(src); + GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_unbind(fx->depth_buffer); + + /* may not be attached, in that case this just returns */ + if (target) { + GPU_framebuffer_texture_detach(target); + if (ofs) { + GPU_offscreen_bind(ofs, false); + } + else { + GPU_framebuffer_restore(); + } } - } - SWAP(GPUTexture *, target, src); - numslots = 0; + SWAP(GPUTexture *, target, src); + numslots = 0; + } } } @@ -976,6 +1242,7 @@ void GPU_fx_compositor_init_dof_settings(GPUDOFSettings *fx_dof) fx_dof->focal_length = 1.0f; fx_dof->focus_distance = 1.0f; fx_dof->sensor = 1.0f; + fx_dof->num_blades = 6; } void GPU_fx_compositor_init_ssao_settings(GPUSSAOSettings *fx_ssao) diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index f16b1525622..24b54a3af37 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -61,6 +61,7 @@ #endif #define MAX_DEFINE_LENGTH 72 +#define MAX_EXT_DEFINE_LENGTH 280 /* Extensions support */ @@ -83,6 +84,9 @@ 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[]; @@ -278,6 +282,16 @@ bool GPU_bicubic_bump_support(void) return GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0; } +bool GPU_geometry_shader_support(void) +{ + return GLEW_EXT_geometry_shader4 || GLEW_VERSION_3_2; +} + +bool GPU_instanced_drawing_support(void) +{ + return GLEW_EXT_draw_instanced; +} + int GPU_color_depth(void) { return GG.colordepth; @@ -736,14 +750,16 @@ GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]) return tex; } -GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, char err_out[256]) +GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]) { GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, err_out); if (tex) { /* Now we tweak some of the settings */ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + if (repeat) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -863,7 +879,7 @@ void GPU_texture_unbind(GPUTexture *tex) GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); } -void GPU_depth_texture_mode(GPUTexture *tex, bool compare, bool use_filter) +void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter) { GLenum arbnumber; @@ -872,11 +888,6 @@ void GPU_depth_texture_mode(GPUTexture *tex, bool compare, bool use_filter) return; } - if (!tex->depth) { - fprintf(stderr, "Not a depth texture."); - return; - } - if (tex->number == -1) return; @@ -884,10 +895,13 @@ void GPU_depth_texture_mode(GPUTexture *tex, bool compare, bool use_filter) arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number); if (tex->number != 0) glActiveTextureARB(arbnumber); - if (compare) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + + if (tex->depth) { + if (compare) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + else + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + } if (use_filter) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -1384,6 +1398,7 @@ struct GPUShader { GLhandleARB object; /* handle for full shader */ GLhandleARB vertex; /* handle for vertex shader */ GLhandleARB fragment; /* handle for fragment shader */ + GLhandleARB geometry; /* handle for geometry shader */ GLhandleARB lib; /* handle for libment shader */ int totattrib; /* total number of attributes */ int uniforms; /* required uniforms */ @@ -1430,13 +1445,19 @@ static const char *gpu_shader_version(void) } -static const char *gpu_shader_standard_extensions(void) +static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH]) { /* need this extensions for high quality bump mapping */ if (GPU_bicubic_bump_support()) - return "#extension GL_ARB_texture_query_lod: enable\n"; + strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n"); - return ""; + if (GPU_geometry_shader_support()) + strcat(defines, "#extension GL_EXT_geometry_shader4: enable\n"); + + if (GPU_instanced_drawing_support()) { + strcat(defines, "#extension GL_EXT_gpu_shader4: enable\n"); + strcat(defines, "#extension GL_EXT_draw_instanced: enable\n"); + } } static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH]) @@ -1457,15 +1478,16 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH]) return; } -GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *libcode, const char *defines) +GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines) { GLint status; GLcharARB log[5000]; GLsizei length = 0; GPUShader *shader; char standard_defines[MAX_DEFINE_LENGTH] = ""; + char standard_extensions[MAX_EXT_DEFINE_LENGTH] = ""; - if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader) + if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader || (geocode && !GPU_geometry_shader_support())) return NULL; shader = MEM_callocN(sizeof(GPUShader), "GPUShader"); @@ -1474,11 +1496,15 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const shader->vertex = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); if (fragcode) shader->fragment = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); + if (geocode) + shader->geometry = glCreateShaderObjectARB(GL_GEOMETRY_SHADER_EXT); + shader->object = glCreateProgramObjectARB(); if (!shader->object || (vertexcode && !shader->vertex) || - (fragcode && !shader->fragment)) + (fragcode && !shader->fragment) || + (geocode && !shader->geometry)) { fprintf(stderr, "GPUShader, object creation failed.\n"); GPU_shader_free(shader); @@ -1486,6 +1512,7 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const } gpu_shader_standard_defines(standard_defines); + gpu_shader_standard_extensions(standard_extensions); if (vertexcode) { const char *source[5]; @@ -1493,11 +1520,11 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const int num_source = 0; source[num_source++] = gpu_shader_version(); - source[num_source++] = gpu_shader_standard_extensions(); + source[num_source++] = standard_extensions; source[num_source++] = standard_defines; if (defines) source[num_source++] = defines; - if (vertexcode) source[num_source++] = vertexcode; + source[num_source++] = vertexcode; glAttachObjectARB(shader->object, shader->vertex); glShaderSourceARB(shader->vertex, num_source, source, NULL); @@ -1519,12 +1546,12 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const int num_source = 0; source[num_source++] = gpu_shader_version(); - source[num_source++] = gpu_shader_standard_extensions(); + source[num_source++] = standard_extensions; source[num_source++] = standard_defines; if (defines) source[num_source++] = defines; if (libcode) source[num_source++] = libcode; - if (fragcode) source[num_source++] = fragcode; + source[num_source++] = fragcode; glAttachObjectARB(shader->object, shader->fragment); glShaderSourceARB(shader->fragment, num_source, source, NULL); @@ -1541,6 +1568,34 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const } } + 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; + if (libcode) source[num_source++] = libcode; + source[num_source++] = geocode; + + glAttachObjectARB(shader->object, shader->geometry); + glShaderSourceARB(shader->geometry, num_source, source, NULL); + + glCompileShaderARB(shader->geometry); + glGetObjectParameterivARB(shader->geometry, GL_OBJECT_COMPILE_STATUS_ARB, &status); + + if (!status) { + glGetInfoLogARB(shader->geometry, sizeof(log), &length, log); + shader_print_errors("compile", log, source, num_source); + + GPU_shader_free(shader); + return NULL; + } + } + + #if 0 if (lib && lib->lib) glAttachObjectARB(shader->object, lib->lib); @@ -1553,6 +1608,7 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const if (fragcode) shader_print_errors("linking", log, &fragcode, 1); else if (vertexcode) shader_print_errors("linking", log, &vertexcode, 1); else if (libcode) shader_print_errors("linking", log, &libcode, 1); + else if (geocode) shader_print_errors("linking", log, &geocode, 1); GPU_shader_free(shader); return NULL; @@ -1648,6 +1704,21 @@ void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int leng 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) glUniform1ivARB(location, arraysize, value); + else if (length == 2) glUniform2ivARB(location, arraysize, value); + else if (length == 3) glUniform3ivARB(location, arraysize, value); + else if (length == 4) glUniform4ivARB(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) @@ -1656,6 +1727,16 @@ void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) GPU_CHECK_ERRORS_AROUND(glUniform1iARB(location, value)); } +void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number) +{ + glProgramParameteriEXT(shader->object, GL_GEOMETRY_INPUT_TYPE_EXT, input); + glProgramParameteriEXT(shader->object, GL_GEOMETRY_OUTPUT_TYPE_EXT, output); + glProgramParameteriEXT(shader->object, GL_GEOMETRY_VERTICES_OUT_EXT, number); + + /* relink so settings can take effect (sucks but should only be done right after compilation so...) */ + glLinkProgramARB(shader->object); +} + void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex) { GLenum arbnumber; @@ -1703,12 +1784,12 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) 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); + GG.shaders.vsm_store = GPU_shader_create(datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, NULL, NULL, NULL); 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); + 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); retval = GG.shaders.sep_gaussian_blur; break; } @@ -1737,38 +1818,60 @@ GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp) } 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, datatoc_gpu_shader_fx_lib_glsl, defines); + 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); 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, datatoc_gpu_shader_fx_lib_glsl, defines); + 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); 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, datatoc_gpu_shader_fx_lib_glsl, defines); + 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); 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, datatoc_gpu_shader_fx_lib_glsl, defines); + 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); 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, datatoc_gpu_shader_fx_lib_glsl, defines); + 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); 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, datatoc_gpu_shader_fx_lib_glsl, defines); + 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); + 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); + 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); + + if (shader) { + GG.shaders.fx_shaders[offset] = shader; + GPU_shader_geometry_stage_primitive_io(shader, GL_POINTS, GL_TRIANGLE_STRIP, 4); + } + 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); 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, defines); + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines); } } diff --git a/source/blender/gpu/intern/gpu_simple_shader.c b/source/blender/gpu/intern/gpu_simple_shader.c index 3fa5975ef15..60d4a2f2875 100644 --- a/source/blender/gpu/intern/gpu_simple_shader.c +++ b/source/blender/gpu/intern/gpu_simple_shader.c @@ -151,6 +151,7 @@ static GPUShader *gpu_simple_shader(int options) shader = GPU_shader_create( datatoc_gpu_shader_simple_vert_glsl, datatoc_gpu_shader_simple_frag_glsl, + NULL, NULL, defines); if (shader) { diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl new file mode 100644 index 00000000000..e2d3ab36ec8 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl @@ -0,0 +1,166 @@ +/* amount of offset to move one pixel left-right. + * In second pass some dimensions are zero to control verical/horizontal convolution */ +uniform vec2 invrendertargetdim; + +uniform ivec2 rendertargetdim; + +/* color buffer */ +uniform sampler2D colorbuffer; +uniform sampler2D farbuffer; +uniform sampler2D nearbuffer; + +/* depth buffer */ +uniform sampler2D depthbuffer; + +uniform sampler2D cocbuffer; + +/* this includes focal distance in x and aperture size in y */ +uniform vec4 dof_params; + +/* viewvectors for reconstruction of world space */ +uniform vec4 viewvecs[3]; + +/* initial uv coordinate */ +varying vec2 uvcoord; + +/* coordinate used for calculating radius et al set in geometry shader */ +varying vec2 particlecoord; +varying vec4 color; + +/* downsampling coordinates */ +varying vec2 downsample1; +varying vec2 downsample2; +varying vec2 downsample3; +varying vec2 downsample4; + +#define M_PI 3.1415926535897932384626433832795 + +/* calculate 4 samples at once */ +vec4 calculate_coc(in vec4 zdepth) +{ + vec4 coc = dof_params.x * (vec4(dof_params.y) / zdepth - vec4(1.0)); + + /* multiply by 1.0 / sensor size to get the normalized size */ + return coc * dof_params.z; +} + +#define THRESHOLD 0.0 + +/* downsample the color buffer to half resolution */ +void downsample_pass() +{ + vec4 depth; + vec4 zdepth; + vec4 coc; + float far_coc, near_coc; + + /* custom downsampling. We need to be careful to sample nearest here to avoid leaks */ + vec4 color1 = texture2D(colorbuffer, downsample1); + vec4 color2 = texture2D(colorbuffer, downsample2); + vec4 color3 = texture2D(colorbuffer, downsample3); + vec4 color4 = texture2D(colorbuffer, downsample4); + + depth.r = texture2D(depthbuffer, downsample1).r; + depth.g = texture2D(depthbuffer, downsample2).r; + depth.b = texture2D(depthbuffer, downsample3).r; + depth.a = texture2D(depthbuffer, downsample4).r; + + zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth); + coc = calculate_coc(zdepth); + vec4 coc_far = -coc; + + /* now we need to write the near-far fields premultiplied by the coc */ + vec4 near_weights = vec4((coc.x >= THRESHOLD) ? 1.0 : 0.0, (coc.y >= THRESHOLD) ? 1.0 : 0.0, + (coc.z >= THRESHOLD) ? 1.0 : 0.0, (coc.w >= THRESHOLD) ? 1.0 : 0.0); + vec4 far_weights = vec4((coc_far.x >= THRESHOLD) ? 1.0 : 0.0, (coc_far.y >= THRESHOLD) ? 1.0 : 0.0, + (coc_far.z >= THRESHOLD) ? 1.0 : 0.0, (coc_far.w >= THRESHOLD) ? 1.0 : 0.0); + + near_coc = max(max(max(coc.x, coc.y), max(coc.z, coc.w)), 0.0); + far_coc = max(max(max(coc_far.x, coc_far.y), max(coc_far.z, coc_far.w)), 0.0); + + float norm_near = dot(near_weights, vec4(1.0)); + float norm_far = dot(far_weights, vec4(1.0)); + + /* now write output to weighted buffers. */ + gl_FragData[0] = color1 * near_weights.x + color2 * near_weights.y + color3 * near_weights.z + + color4 * near_weights.w; + gl_FragData[1] = color1 * far_weights.x + color2 * far_weights.y + color3 * far_weights.z + + color4 * far_weights.w; + + if (norm_near > 0.0) + gl_FragData[0] /= norm_near; + if (norm_far > 0.0) + gl_FragData[1] /= norm_far; + gl_FragData[2] = vec4(near_coc, far_coc, 0.0, 1.0); +} + +/* accumulate color in the near/far blur buffers */ +void accumulate_pass(void) { + float theta = atan(particlecoord.y, particlecoord.x); + float r; + + if (dof_params.w == 0.0) + r = 1.0; + else + r = cos(M_PI / dof_params.w) / (cos(theta - (2.0 * M_PI / dof_params.w) * floor((dof_params.w * theta + M_PI) / (2 * M_PI)))); + + if (dot(particlecoord, particlecoord) > r * r) + discard; + + gl_FragColor = color; +} +#define MERGE_THRESHOLD 4.0 + +/* combine the passes, */ +void final_pass(void) { + vec4 finalcolor; + float totalweight; + float depth = texture2D(depthbuffer, uvcoord).r; + + vec4 zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), vec4(depth)); + float coc_near = calculate_coc(zdepth).r; + float coc_far = max(-coc_near, 0.0); + coc_near = max(coc_near, 0.0); + + vec4 farcolor = texture2D(farbuffer, uvcoord); + float farweight = farcolor.a; + if (farweight > 0) + farcolor /= farweight; + vec4 nearcolor = texture2D(nearbuffer, uvcoord); + + vec4 srccolor = texture2D(colorbuffer, uvcoord); + + vec4 coc = texture2D(cocbuffer, uvcoord); + + float mixfac = smoothstep(1.0, MERGE_THRESHOLD, coc_far); + finalcolor = mix(srccolor, farcolor, mixfac); + + farweight = mix(1.0, farweight, mixfac); + + float nearweight = nearcolor.a; + if (nearweight > 0) { + nearcolor /= nearweight; + } + + if (coc_near > 1.0) { + nearweight = 1.0; + finalcolor = nearcolor; + } + else { + totalweight = nearweight + farweight; + finalcolor = mix(finalcolor, nearcolor, nearweight / totalweight); + } + + gl_FragColor = finalcolor; +} + +void main() +{ +#ifdef FIRST_PASS + downsample_pass(); +#elif defined(SECOND_PASS) + accumulate_pass(); +#elif defined(THIRD_PASS) + final_pass(); +#endif +} diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl new file mode 100644 index 00000000000..9f365a0d671 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl @@ -0,0 +1,50 @@ +uniform ivec2 rendertargetdim; +uniform sampler2D colorbuffer; + +uniform vec2 layerselection; + +uniform sampler2D cocbuffer; + +/* initial uv coordinate */ +varying in vec2 uvcoord[]; +varying out vec2 particlecoord; +varying out vec4 color; + + +#define M_PI 3.1415926535897932384626433832795 + +void main(void) +{ + vec4 coc = texture2DLod(cocbuffer, uvcoord[0], 0.0); + + float offset_val = dot(coc.rg, layerselection); + if (offset_val < 1.0) + return; + + vec4 colortex = texture2DLod(colorbuffer, uvcoord[0], 0.0); + + /* find the area the pixel will cover and divide the color by it */ + float alpha = 1.0 / (offset_val * offset_val * M_PI); + colortex *= alpha; + colortex.a = alpha; + + vec2 offset_far = vec2(offset_val * 0.5) / vec2(rendertargetdim.x, rendertargetdim.y); + + gl_Position = gl_PositionIn[0] + vec4(-offset_far.x, -offset_far.y, 0.0, 0.0); + color = colortex; + particlecoord = vec2(-1.0, -1.0); + EmitVertex(); + gl_Position = gl_PositionIn[0] + vec4(-offset_far.x, offset_far.y, 0.0, 0.0); + particlecoord = vec2(-1.0, 1.0); + color = colortex; + EmitVertex(); + gl_Position = gl_PositionIn[0] + vec4(offset_far.x, -offset_far.y, 0.0, 0.0); + particlecoord = vec2(1.0, -1.0); + color = colortex; + EmitVertex(); + gl_Position = gl_PositionIn[0] + vec4(offset_far.x, offset_far.y, 0.0, 0.0); + particlecoord = vec2(1.0, 1.0); + color = colortex; + EmitVertex(); + EndPrimitive(); +} diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl new file mode 100644 index 00000000000..e8c505bd15f --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl @@ -0,0 +1,58 @@ +uniform vec2 invrendertargetdim; +uniform ivec2 rendertargetdim; +/* initial uv coordinate */ +varying vec2 uvcoord; + +/* coordinate used for calculating radius et al set in geometry shader */ +varying vec2 particlecoord; + +/* downsampling coordinates */ +varying vec2 downsample1; +varying vec2 downsample2; +varying vec2 downsample3; +varying vec2 downsample4; + +void vert_dof_downsample() +{ + /* gather pixels from neighbors. half dimensions means we offset half a pixel to + * get this right though it's possible we may lose a pixel at some point */ + downsample1 = gl_MultiTexCoord0.xy + vec2(-0.5, -0.5) * invrendertargetdim; + downsample2 = gl_MultiTexCoord0.xy + vec2(-0.5, 0.5) * invrendertargetdim; + downsample3 = gl_MultiTexCoord0.xy + vec2(0.5, 0.5) * invrendertargetdim; + downsample4 = gl_MultiTexCoord0.xy + vec2(0.5, -0.5) * invrendertargetdim; + + gl_Position = gl_Vertex; +} + +/* geometry shading pass, calculate a texture coordinate based on the indexed id */ +void vert_dof_coc_scatter_pass() +{ + vec2 pixel = vec2(1.0 / float(rendertargetdim.x), 1.0 / float(rendertargetdim.y)); + /* some math to get the target pixel */ + int row = gl_InstanceID / rendertargetdim.x; + int column = gl_InstanceID % rendertargetdim.x; + uvcoord = vec2(column, row) * pixel + 0.5 * pixel; + + vec2 pos = uvcoord * 2.0 - vec2(1.0); + gl_Position = vec4(pos.x, pos.y, 0.0, 1.0); + +// uvcoord = vec2(0.5, 0.5); +// gl_Position = vec4(0.0, 0.0, 0.0, 1.0); +} + +void vert_dof_final() +{ + uvcoord = gl_MultiTexCoord0.xy; + gl_Position = gl_Vertex; +} + +void main() +{ +#if defined(FIRST_PASS) + vert_dof_downsample(); +#elif defined(SECOND_PASS) + vert_dof_coc_scatter_pass(); +#else + vert_dof_final(); +#endif +}
\ No newline at end of file diff --git a/source/blender/makesdna/DNA_gpu_types.h b/source/blender/makesdna/DNA_gpu_types.h index b6009b3f899..967cb7284dc 100644 --- a/source/blender/makesdna/DNA_gpu_types.h +++ b/source/blender/makesdna/DNA_gpu_types.h @@ -38,6 +38,8 @@ typedef struct GPUDOFSettings { float fstop; float focal_length; float sensor; + int num_blades; + int high_quality; } GPUDOFSettings; /* properties for SSAO effect */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 629fbbf66e9..4214c830e4c 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -1745,6 +1745,19 @@ static void rna_GPUFXSettings_fx_update(Main *UNUSED(bmain), Scene *UNUSED(scene BKE_screen_gpu_fx_validate(fx_settings); } +static void rna_GPUDOFSettings_blades_set(PointerRNA *ptr, const int value) +{ + GPUDOFSettings *dofsettings = (GPUDOFSettings *)ptr->data; + + if (value < 3 && dofsettings->num_blades > 2) + dofsettings->num_blades = 0; + else if (value > 0 && dofsettings->num_blades == 0) + dofsettings->num_blades = 3; + else + dofsettings->num_blades = value; +} + + #else static void rna_def_transform_orientation(BlenderRNA *brna) @@ -3908,6 +3921,17 @@ static void rna_def_gpu_dof_fx(BlenderRNA *brna) RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_ui_range(prop, 0.1f, 128.0f, 10, 1); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "num_blades", PROP_INT, PROP_NONE); + RNA_def_property_ui_text(prop, "Viewport Camera Blades", "Blades for dof effect"); + RNA_def_property_range(prop, 0, 16); + RNA_def_property_int_funcs(prop, NULL, "rna_GPUDOFSettings_blades_set", NULL); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "high_quality", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "high_quality", 1); + RNA_def_property_ui_text(prop, "High Quality", "Use high quality depth of field"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); } static void rna_def_gpu_ssao_fx(BlenderRNA *brna) |