Depth of field high quality:
authorAntony Riakiotakis <kalast@gmail.com>
Tue, 3 Mar 2015 16:47:31 +0000 (17:47 +0100)
committerAntony Riakiotakis <kalast@gmail.com>
Thu, 19 Mar 2015 14:18:14 +0000 (15:18 +0100)
A new checkbox "High quality" is provided in camera settings to enable
this. This creates a depth of field that is much closer to the rendered
result and even supports aperture blades in the effect, but it's more
expensive too. There are optimizations to do here since the technique is
very fill rate heavy.

People, be careful, this -can- lock up your screen if depth of field
blurring is too extreme.

Technical details:

This uses geometry shaders + instancing and is an adaptation of
techniques gathered from

http://bartwronski.com/2014/04/07/bokeh-depth-of-field-going-insane-

 http://advances.realtimerendering.com/s2011/SousaSchulzKazyan%20-
%20in%20Real-Time%20Rendering%20Course).ppt

TODOs:

* Support dithering to minimize banding.
* Optimize fill rate in geometry shader.

14 files changed:
intern/cycles/blender/addon/ui.py
release/scripts/startup/bl_ui/properties_data_camera.py
source/blender/gpu/CMakeLists.txt
source/blender/gpu/GPU_compositing.h
source/blender/gpu/GPU_extensions.h
source/blender/gpu/intern/gpu_codegen.c
source/blender/gpu/intern/gpu_compositing.c
source/blender/gpu/intern/gpu_extensions.c
source/blender/gpu/intern/gpu_simple_shader.c
source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl [new file with mode: 0644]
source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl [new file with mode: 0644]
source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl [new file with mode: 0644]
source/blender/makesdna/DNA_gpu_types.h
source/blender/makesrna/intern/rna_scene.c

index 63518d7fdb6974ab9e6c68078a5075b409168a0c..b0337a69e7d3b585d8440316b853cf5b67843cf0 100644 (file)
@@ -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:")
index 106e31ea89a9a0a991bec3569a3e26ae7fb377d3..2097e82f992c13786a55ac066308c5286d1a2b53 100644 (file)
@@ -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")
index b5d9028a8ae1e106c04de8ffb8b14f6f09d40c9b..97b0e7e1e0e0f60058c74656a58b80336dbe47a8 100644 (file)
@@ -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)
 
index 93f1bc649228e7bb4b12c7bfd4cb7b1291ec67d5..5589084705b1b222c3b74101c1df16129664298f 100644 (file)
@@ -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);
index 985cebc86875c34aa4eff4c9fb402ba556639c46..aed1a88938a99d27fac791a96cad48925c31a432 100644 (file)
@@ -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);
 
index 40c9ec0d862f59ad206d4381ce7680db0756e726..fcfb68d4629f4866398980c05af7e8f85555bf5c 100644 (file)
@@ -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) {
index 511167b775af8a8b5b17201ffc810e56be11bc2d..bfa938d0fed3627177dad7a8d50611218b73293e 100644 (file)
@@ -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)
index f16b1525622dc852a2d0969dc38927a0771e1375..24b54a3af374b40b56a13ddb958210f5007a5f7a 100644 (file)
@@ -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);
                }
        }
 
index 3fa5975ef157f42bec9c1999d6950e748a0a5e3e..60d4a2f287553bff15b8b5d556f1792e4f03a109 100644 (file)
@@ -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 (file)
index 0000000..e2d3ab3
--- /dev/null
@@ -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 (file)
index 0000000..9f365a0
--- /dev/null
@@ -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 (file)
index 0000000..e8c505b
--- /dev/null
@@ -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
index b6009b3f89981511ac88f71c12a4b3f94668746e..967cb7284dc327538818a016d496b31f7787b46b 100644 (file)
@@ -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 */
index 629fbbf66e9b417ed54263a5efa4dc49ae6275b9..4214c830e4c1a11980a1a01de0b211c259e5849d 100644 (file)
@@ -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)