Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/gpu')
-rw-r--r--source/blender/gpu/CMakeLists.txt21
-rw-r--r--source/blender/gpu/GPU_compositing.h88
-rw-r--r--source/blender/gpu/GPU_extensions.h24
-rw-r--r--source/blender/gpu/SConscript5
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c2
-rw-r--r--source/blender/gpu/intern/gpu_compositing.c863
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c258
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl206
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl68
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_lib.glsl47
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl82
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_vert.glsl9
12 files changed, 1640 insertions, 33 deletions
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 361c247767f..7e32105a916 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -54,6 +54,21 @@ set(SRC
intern/gpu_material.c
intern/gpu_simple_shader.c
intern/gpu_select.c
+ intern/gpu_compositing.c
+
+ shaders/gpu_shader_fx_lib.glsl
+ 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_vert.glsl
+ shaders/gpu_shader_material.glsl
+ shaders/gpu_shader_sep_gaussian_blur_frag.glsl
+ shaders/gpu_shader_sep_gaussian_blur_vert.glsl
+ shaders/gpu_shader_simple_frag.glsl
+ shaders/gpu_shader_simple_vert.glsl
+ shaders/gpu_shader_vertex.glsl
+ shaders/gpu_shader_vsm_store_frag.glsl
+ shaders/gpu_shader_vsm_store_vert.glsl
GPU_buffers.h
GPU_draw.h
@@ -63,6 +78,7 @@ set(SRC
GPU_material.h
GPU_simple_shader.h
GPU_select.h
+ GPU_compositing.h
intern/gpu_codegen.h
intern/gpu_extensions_private.h
)
@@ -76,6 +92,11 @@ data_to_c_simple(shaders/gpu_shader_vertex.glsl SRC)
data_to_c_simple(shaders/gpu_shader_vertex_world.glsl SRC)
data_to_c_simple(shaders/gpu_shader_vsm_store_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_vsm_store_vert.glsl SRC)
+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_lib.glsl SRC)
if(WITH_GAMEENGINE)
add_definitions(-DWITH_GAMEENGINE)
diff --git a/source/blender/gpu/GPU_compositing.h b/source/blender/gpu/GPU_compositing.h
new file mode 100644
index 00000000000..796341d4830
--- /dev/null
+++ b/source/blender/gpu/GPU_compositing.h
@@ -0,0 +1,88 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Antony Riakiotakis.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file GPU_compositing.h
+ * \ingroup gpu
+ */
+
+#ifndef __GPU_COMPOSITING_H__
+#define __GPU_COMPOSITING_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* opaque handle for framebuffer compositing effects (defined in gpu_compositing.c )*/
+typedef struct GPUFX GPUFX;
+struct GPUDOFSettings;
+struct GPUSSAOSettings;
+struct GPUOffScreen;
+struct GPUFXSettings;
+struct RegionView3D;
+struct rcti;
+struct Scene;
+struct View3D;
+enum eGPUFXFlags;
+
+/**** Public API *****/
+
+typedef enum GPUFXShaderEffect {
+ /* Screen space ambient occlusion shader */
+ GPU_SHADER_FX_SSAO = 1,
+
+ /* depth of field passes. Yep, quite a complex effect */
+ GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE = 2,
+ GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO = 3,
+ GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE = 4,
+ GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR = 5,
+ GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE = 6,
+} GPUFXShaderEffect;
+
+/* keep in synch with enum above! */
+#define MAX_FX_SHADERS 11
+
+/* generate a new FX compositor */
+GPUFX *GPU_fx_compositor_create(void);
+
+/* destroy a text compositor */
+void GPU_fx_compositor_destroy(GPUFX *fx);
+
+/* initialize a framebuffer with size taken from the viewport */
+bool GPU_fx_compositor_initialize_passes(
+ GPUFX *fx, const struct rcti *rect, const struct rcti *scissor_rect,
+ const struct GPUFXSettings *fx_settings);
+
+/* do compositing on the fx passes that have been initialized */
+bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, struct Scene *scene, struct GPUOffScreen *ofs);
+
+void GPU_fx_compositor_init_dof_settings(struct GPUDOFSettings *dof);
+void GPU_fx_compositor_init_ssao_settings(struct GPUSSAOSettings *ssao);
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __GPU_COMPOSITING_H__
diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h
index bb0cf2dd2b9..739d45663f8 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_extensions.h
@@ -107,11 +107,19 @@ int GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver);
* - if created with from_blender, will not free the texture
*/
+typedef enum GPUHDRType {
+ GPU_HDR_NONE = 0,
+ GPU_HDR_HALF_FLOAT = 1,
+ GPU_HDR_FULL_FLOAT = (1 << 1),
+} GPUHDRType;
+
GPUTexture *GPU_texture_create_1D(int w, float *pixels, char err_out[256]);
-GPUTexture *GPU_texture_create_2D(int w, int h, float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_2D(int w, int h, float *pixels, GPUHDRType hdr, char err_out[256]);
GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, 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, float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_1D_procedural(int w, float *pixels, char err_out[256]);
GPUTexture *GPU_texture_from_blender(struct Image *ima,
struct ImageUser *iuser, bool is_data, double time, int mipmap);
GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap);
@@ -126,6 +134,8 @@ 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);
+
GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex);
int GPU_texture_target(GPUTexture *tex);
@@ -145,11 +155,13 @@ void GPU_texture_bind_as_framebuffer(GPUTexture *tex);
GPUFrameBuffer *GPU_framebuffer_create(void);
int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]);
void GPU_framebuffer_texture_detach(GPUTexture *tex);
-void GPU_framebuffer_slot_bind(GPUFrameBuffer *fb, int slot);
+void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot);
void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, GPUTexture *tex);
void GPU_framebuffer_free(GPUFrameBuffer *fb);
bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]);
+void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot);
+
void GPU_framebuffer_restore(void);
void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex);
@@ -159,8 +171,8 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b
GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256]);
void GPU_offscreen_free(GPUOffScreen *ofs);
-void GPU_offscreen_bind(GPUOffScreen *ofs);
-void GPU_offscreen_unbind(GPUOffScreen *ofs);
+void GPU_offscreen_bind(GPUOffScreen *ofs, bool save);
+void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore);
void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels);
int GPU_offscreen_width(GPUOffScreen *ofs);
int GPU_offscreen_height(GPUOffScreen *ofs);
@@ -177,7 +189,7 @@ 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, float *value);
+ int arraysize, const float *value);
void GPU_shader_uniform_texture(GPUShader *shader, int location, GPUTexture *tex);
void GPU_shader_uniform_int(GPUShader *shader, int location, int value);
@@ -190,6 +202,8 @@ typedef enum GPUBuiltinShader {
} GPUBuiltinShader;
GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader);
+GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp);
+
void GPU_shader_free_builtin_shaders(void);
/* Vertex attributes for shaders */
diff --git a/source/blender/gpu/SConscript b/source/blender/gpu/SConscript
index e44a99286a8..158cfb67dda 100644
--- a/source/blender/gpu/SConscript
+++ b/source/blender/gpu/SConscript
@@ -65,6 +65,11 @@ import os
sources.extend((
os.path.join(env['DATA_SOURCES'], "gpu_shader_simple_frag.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_simple_vert.glsl.c"),
+ os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_ssao_frag.glsl.c"),
+ os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_frag.glsl.c"),
+ os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_vert.glsl.c"),
+ os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_lib.glsl.c"),
+ os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_vert.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_material.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_sep_gaussian_blur_frag.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_sep_gaussian_blur_vert.glsl.c"),
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 97064f43f5d..9e4d0d5f823 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -972,7 +972,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
input->textype = type;
//input->tex = GPU_texture_create_2D(link->texturesize, link->texturesize, link->ptr2, NULL);
- input->tex = GPU_texture_create_2D(link->texturesize, 1, link->ptr1, NULL);
+ input->tex = GPU_texture_create_2D(link->texturesize, 1, link->ptr1, GPU_HDR_NONE, NULL);
input->textarget = GL_TEXTURE_2D;
MEM_freeN(link->ptr1);
diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c
new file mode 100644
index 00000000000..b423c14bd4b
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_compositing.c
@@ -0,0 +1,863 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Antony Riakiotakis.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_compositing.c
+ * \ingroup gpu
+ *
+ * System that manages framebuffer compositing.
+ */
+
+#include "BLI_sys_types.h"
+#include "BLI_rect.h"
+#include "BLI_math.h"
+#include "BLI_listbase.h"
+#include "BLI_linklist.h"
+
+#include "BLI_rand.h"
+#include "BLI_listbase.h"
+
+#include "DNA_vec_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_gpu_types.h"
+
+#include "GPU_extensions.h"
+#include "GPU_compositing.h"
+
+#include "GL/glew.h"
+
+#include "MEM_guardedalloc.h"
+
+static const float fullscreencos[4][2] = {{-1.0f, -1.0f}, {1.0f, -1.0f}, {-1.0f, 1.0f}, {1.0f, 1.0f}};
+static const float fullscreenuvs[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}};
+
+struct GPUFX {
+ /* we borrow the term gbuffer from deferred rendering however this is just a regular
+ * depth/color framebuffer. Could be extended later though */
+ GPUFrameBuffer *gbuffer;
+
+ /* texture bound to the first color attachment of the gbuffer */
+ GPUTexture *color_buffer;
+
+ /* second texture used for ping-pong compositing */
+ GPUTexture *color_buffer_sec;
+
+ /* all those buffers below have to coexist. Fortunately they are all quarter sized (1/16th of memory) of original framebuffer */
+ int dof_downsampled_w;
+ int dof_downsampled_h;
+
+ /* texture used for near coc and color blurring calculation */
+ GPUTexture *dof_near_coc_buffer;
+ /* blurred near coc buffer. */
+ GPUTexture *dof_near_coc_blurred_buffer;
+ /* final near coc buffer. */
+ 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_near_blur;
+ GPUTexture *dof_far_blur;
+ GPUTexture *dof_concentric_samples_tex;
+
+ /* texture bound to the depth attachment of the gbuffer */
+ GPUTexture *depth_buffer;
+
+ /* texture used for jittering for various effects */
+ GPUTexture *jitter_buffer;
+
+ /* texture used for ssao */
+ int ssao_sample_count;
+ GPUTexture *ssao_concentric_samples_tex;
+
+ /* dimensions of the gbuffer */
+ int gbuffer_dim[2];
+
+ GPUFXSettings settings;
+
+ /* or-ed flags of enabled effects */
+ int effects;
+
+ /* number of passes, needed to detect if ping pong buffer allocation is needed */
+ int num_passes;
+
+ /* we have a stencil, restore the previous state */
+ bool restore_stencil;
+};
+
+/* concentric mapping, see "A Low Distortion Map Between Disk and Square" and
+ * http://psgraphics.blogspot.nl/2011/01/improved-code-for-concentric-map.html */
+static GPUTexture * create_concentric_sample_texture(int side)
+{
+ GPUTexture *tex;
+ float midpoint = 0.5f * (side - 1);
+ float *texels = (float *)MEM_mallocN(sizeof(float) * 2 * side * side, "concentric_tex");
+ int i, j;
+
+ for (i = 0; i < side; i++) {
+ for (j = 0; j < side; j++) {
+ int index = (i * side + j) * 2;
+ float a = 1.0f - i / midpoint;
+ float b = 1.0f - j / midpoint;
+ float phi, r;
+ if (a * a > b * b) {
+ r = a;
+ phi = (M_PI_4) * (b / a);
+ }
+ else {
+ r = b;
+ phi = M_PI_2 - (M_PI_4) * (a / b);
+ }
+ texels[index] = r * cos(phi);
+ texels[index + 1] = r * sin(phi);
+ }
+ }
+
+ tex = GPU_texture_create_1D_procedural(side * side, texels, NULL);
+ MEM_freeN(texels);
+ return tex;
+}
+
+/* generate a new FX compositor */
+GPUFX *GPU_fx_compositor_create(void)
+{
+ GPUFX *fx = MEM_callocN(sizeof(GPUFX), "GPUFX compositor");
+
+ return fx;
+}
+
+static void cleanup_fx_dof_buffers(GPUFX *fx)
+{
+ if (fx->dof_near_coc_blurred_buffer) {
+ GPU_texture_free(fx->dof_near_coc_blurred_buffer);
+ fx->dof_near_coc_blurred_buffer = NULL;
+ }
+ if (fx->dof_near_coc_buffer) {
+ GPU_texture_free(fx->dof_near_coc_buffer);
+ fx->dof_near_coc_buffer = NULL;
+ }
+ if (fx->dof_near_coc_final_buffer) {
+ GPU_texture_free(fx->dof_near_coc_final_buffer);
+ 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_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_near_blur) {
+ GPU_texture_free(fx->dof_near_blur);
+ fx->dof_near_blur = NULL;
+ }
+ if (fx->dof_far_blur) {
+ 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)
+{
+ if (fx->color_buffer) {
+ GPU_framebuffer_texture_detach(fx->color_buffer);
+ GPU_texture_free(fx->color_buffer);
+ fx->color_buffer = NULL;
+ }
+
+ if (fx->color_buffer_sec) {
+ GPU_framebuffer_texture_detach(fx->color_buffer_sec);
+ GPU_texture_free(fx->color_buffer_sec);
+ fx->color_buffer_sec = NULL;
+ }
+
+ if (fx->depth_buffer) {
+ GPU_framebuffer_texture_detach(fx->depth_buffer);
+ GPU_texture_free(fx->depth_buffer);
+ fx->depth_buffer = NULL;
+ }
+
+ 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->jitter_buffer && do_fbo) {
+ GPU_texture_free(fx->jitter_buffer);
+ fx->jitter_buffer = NULL;
+ }
+
+ if (fx->gbuffer && do_fbo) {
+ GPU_framebuffer_free(fx->gbuffer);
+ fx->gbuffer = NULL;
+ }
+}
+
+/* destroy a text compositor */
+void GPU_fx_compositor_destroy(GPUFX *fx)
+{
+ cleanup_fx_gl_data(fx, true);
+ MEM_freeN(fx);
+}
+
+static GPUTexture * create_jitter_texture(void)
+{
+ float jitter [64 * 64][2];
+ int i;
+
+ for (i = 0; i < 64 * 64; i++) {
+ jitter[i][0] = 2.0f * BLI_frand() - 1.0;
+ jitter[i][1] = 2.0f * BLI_frand() - 1.0;
+ normalize_v2(jitter[i]);
+ }
+
+ return GPU_texture_create_2D_procedural(64, 64, &jitter[0][0], NULL);
+}
+
+
+bool GPU_fx_compositor_initialize_passes(
+ GPUFX *fx, const rcti *rect, const rcti *scissor_rect,
+ const GPUFXSettings *fx_settings)
+{
+ int w = BLI_rcti_size_x(rect) + 1, h = BLI_rcti_size_y(rect) + 1;
+ char err_out[256];
+ int num_passes = 0;
+ char fx_flag = fx_settings->fx_flag;
+
+ fx->effects = 0;
+
+ if (!fx_settings) {
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+
+ /* disable effects if no options passed for them */
+ if (!fx_settings->dof) {
+ fx_flag &= ~GPU_FX_FLAG_DOF;
+ }
+ if (!fx_settings->ssao || fx_settings->ssao->samples < 1) {
+ fx_flag &= ~GPU_FX_FLAG_SSAO;
+ }
+
+ if (!fx_flag) {
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+
+ fx->num_passes = 0;
+ /* dof really needs a ping-pong buffer to work */
+ if (fx_flag & GPU_FX_FLAG_DOF)
+ num_passes++;
+
+ if (fx_flag & GPU_FX_FLAG_SSAO)
+ num_passes++;
+
+ if (!fx->gbuffer)
+ fx->gbuffer = GPU_framebuffer_create();
+
+ /* try creating the jitter texture */
+ if (!fx->jitter_buffer)
+ fx->jitter_buffer = create_jitter_texture();
+
+ if (!fx->gbuffer)
+ return false;
+
+ /* check if color buffers need recreation */
+ if (!fx->color_buffer || !fx->depth_buffer || w != fx->gbuffer_dim[0] || h != fx->gbuffer_dim[1]) {
+ cleanup_fx_gl_data(fx, false);
+
+ if (!(fx->color_buffer = GPU_texture_create_2D(w, h, NULL, GPU_HDR_NONE, err_out))) {
+ printf(".256%s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+
+ if (!(fx->depth_buffer = GPU_texture_create_depth(w, h, err_out))) {
+ printf("%.256s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+ }
+
+ 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 < 1)
+ fx_settings->ssao->samples = 1;
+
+ fx->ssao_sample_count = fx_settings->ssao->samples;
+
+ if (fx->ssao_concentric_samples_tex) {
+ GPU_texture_free(fx->ssao_concentric_samples_tex);
+ }
+
+ fx->ssao_concentric_samples_tex = create_concentric_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;
+ }
+ }
+
+ /* 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) {
+ 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;
+ }
+ }
+ }
+ else {
+ /* cleanup unnecessary buffers */
+ cleanup_fx_dof_buffers(fx);
+ }
+
+ /* we need to pass data between shader stages, allocate an extra color buffer */
+ if (num_passes > 1) {
+ if(!fx->color_buffer_sec) {
+ if (!(fx->color_buffer_sec = GPU_texture_create_2D(w, h, NULL, GPU_HDR_NONE, err_out))) {
+ printf(".256%s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+ }
+ }
+ else {
+ if (fx->color_buffer_sec) {
+ GPU_framebuffer_texture_detach(fx->color_buffer_sec);
+ GPU_texture_free(fx->color_buffer_sec);
+ fx->color_buffer_sec = NULL;
+ }
+ }
+
+ /* bind the buffers */
+
+ /* first depth buffer, because system assumes read/write buffers */
+ if(!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, err_out))
+ printf("%.256s\n", err_out);
+
+ if(!GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0, err_out))
+ printf("%.256s\n", err_out);
+
+ if(!GPU_framebuffer_check_valid(fx->gbuffer, err_out))
+ printf("%.256s\n", err_out);
+
+ GPU_texture_bind_as_framebuffer(fx->color_buffer);
+
+ /* enable scissor test. It's needed to ensure sculpting works correctly */
+ if (scissor_rect) {
+ int w_sc = BLI_rcti_size_x(scissor_rect) + 1;
+ int h_sc = BLI_rcti_size_y(scissor_rect) + 1;
+ glPushAttrib(GL_SCISSOR_BIT);
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(scissor_rect->xmin - rect->xmin, scissor_rect->ymin - rect->ymin,
+ w_sc, h_sc);
+ fx->restore_stencil = true;
+ }
+ else {
+ fx->restore_stencil = false;
+ }
+
+ fx->effects = fx_flag;
+
+ if (fx_settings)
+ fx->settings = *fx_settings;
+ fx->gbuffer_dim[0] = w;
+ fx->gbuffer_dim[1] = h;
+
+ fx->num_passes = num_passes;
+
+ return true;
+}
+
+static void gpu_fx_bind_render_target(int *passes_left, GPUFX *fx, struct GPUOffScreen *ofs, GPUTexture *target)
+{
+ if ((*passes_left)-- == 1) {
+ GPU_framebuffer_texture_unbind(fx->gbuffer, NULL);
+ if (ofs) {
+ GPU_offscreen_bind(ofs, false);
+ }
+ else
+ GPU_framebuffer_restore();
+ }
+ else {
+ /* bind the ping buffer to the color buffer */
+ GPU_framebuffer_texture_attach(fx->gbuffer, target, 0, NULL);
+ }
+}
+
+bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, struct Scene *scene, struct GPUOffScreen *ofs)
+{
+ GPUTexture *src, *target;
+ int numslots = 0;
+ float invproj[4][4];
+ int i;
+ /* number of passes left. when there are no more passes, the result is passed to the frambuffer */
+ int passes_left = fx->num_passes;
+ /* view vectors for the corners of the view frustum. Can be used to recreate the world space position easily */
+ float viewvecs[3][4] = {
+ {-1.0f, -1.0f, -1.0f, 1.0f},
+ {1.0f, -1.0f, -1.0f, 1.0f},
+ {-1.0f, 1.0f, -1.0f, 1.0f}
+ };
+
+ if (fx->effects == 0)
+ return false;
+
+ /* first, unbind the render-to-texture framebuffer */
+ GPU_framebuffer_texture_detach(fx->color_buffer);
+ GPU_framebuffer_texture_detach(fx->depth_buffer);
+
+ if (fx->restore_stencil)
+ glPopAttrib();
+
+ src = fx->color_buffer;
+ target = fx->color_buffer_sec;
+
+ /* set up quad buffer */
+ glVertexPointer(2, GL_FLOAT, 0, fullscreencos);
+ glTexCoordPointer(2, GL_FLOAT, 0, fullscreenuvs);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ /* full screen FX pass */
+
+ /* invert the view matrix */
+ invert_m4_m4(invproj, projmat);
+
+ /* convert the view vectors to view space */
+ for (i = 0; i < 3; i++) {
+ mul_m4_v4(invproj, viewvecs[i]);
+ /* normalized trick see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
+ mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]);
+ if (is_persp)
+ mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]);
+ viewvecs[i][3] = 1.0;
+ }
+
+ /* we need to store the differences */
+ viewvecs[1][0] -= viewvecs[0][0];
+ viewvecs[1][1] = viewvecs[2][1] - viewvecs[0][1];
+
+ /* calculate a depth offset as well */
+ if (!is_persp) {
+ float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f};
+ mul_m4_v4(invproj, vec_far);
+ mul_v3_fl(vec_far, 1.0f / vec_far[3]);
+ viewvecs[1][2] = vec_far[2] - viewvecs[0][2];
+ }
+
+ /* set invalid color in case shader fails */
+ glColor3f(1.0, 0.0, 1.0);
+ glDisable(GL_DEPTH_TEST);
+
+ /* ssao pass */
+ if (fx->effects & GPU_FX_FLAG_SSAO) {
+ GPUShader *ssao_shader;
+ ssao_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_SSAO, is_persp);
+ if (ssao_shader) {
+ const GPUSSAOSettings *fx_ssao = fx->settings.ssao;
+ int color_uniform, depth_uniform;
+ int ssao_uniform, ssao_color_uniform, viewvecs_uniform, ssao_sample_params_uniform;
+ int ssao_jitter_uniform, ssao_concentric_tex;
+ 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 * fx->ssao_sample_count;
+ /* 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;
+
+ ssao_uniform = GPU_shader_get_uniform(ssao_shader, "ssao_params");
+ ssao_color_uniform = GPU_shader_get_uniform(ssao_shader, "ssao_color");
+ color_uniform = GPU_shader_get_uniform(ssao_shader, "colorbuffer");
+ depth_uniform = GPU_shader_get_uniform(ssao_shader, "depthbuffer");
+ viewvecs_uniform = GPU_shader_get_uniform(ssao_shader, "viewvecs");
+ ssao_sample_params_uniform = GPU_shader_get_uniform(ssao_shader, "ssao_sample_params");
+ ssao_concentric_tex = GPU_shader_get_uniform(ssao_shader, "ssao_concentric_tex");
+ ssao_jitter_uniform = GPU_shader_get_uniform(ssao_shader, "jitter_tex");
+
+ GPU_shader_bind(ssao_shader);
+
+ GPU_shader_uniform_vector(ssao_shader, ssao_uniform, 4, 1, ssao_params);
+ GPU_shader_uniform_vector(ssao_shader, ssao_color_uniform, 4, 1, fx_ssao->color);
+ GPU_shader_uniform_vector(ssao_shader, viewvecs_uniform, 4, 3, viewvecs[0]);
+ GPU_shader_uniform_vector(ssao_shader, ssao_sample_params_uniform, 4, 1, sample_params);
+
+ GPU_texture_bind(src, numslots++);
+ 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_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);
+
+ /* draw */
+ gpu_fx_bind_render_target(&passes_left, fx, ofs, target);
+
+ 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_texture_unbind(fx->jitter_buffer);
+ GPU_texture_unbind(fx->ssao_concentric_samples_tex);
+
+ /* 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 here, after src/target have been unbound */
+ SWAP(GPUTexture *, target, src);
+ numslots = 0;
+ }
+ }
+
+ /* 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;
+ float scale_camera = 0.001f / scale;
+ float aperture = 2.0f * scale_camera * fx_dof->focal_length / fx_dof->fstop;
+
+ dof_params[0] = aperture * fabs(scale_camera * fx_dof->focal_length / (fx_dof->focus_distance - scale_camera * fx_dof->focal_length));
+ dof_params[1] = fx_dof->focus_distance;
+ 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;
+ }
+
+ /* pass first, first level of blur in low res buffer */
+ {
+ int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform;
+ int viewvecs_uniform;
+
+ float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]};
+
+ 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");
+
+ 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_texture_bind(src, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass1, color_uniform, src);
+
+ 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);
+
+ /* 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);
+
+ 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_framebuffer_texture_detach(fx->dof_near_coc_buffer);
+ numslots = 0;
+ }
+
+ /* 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;
+
+ dof_params[2] = GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer) / (scale_camera * fx_dof->sensor);
+
+ 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");
+
+ /* Blurring vertically */
+ GPU_shader_bind(dof_shader_pass2);
+
+ 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_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(fx->dof_near_coc_buffer, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_buffer);
+
+ /* use final buffer as a temp here */
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL);
+
+ /* Drawing quad */
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ /* *unbind/detach */
+ GPU_texture_unbind(fx->dof_near_coc_buffer);
+ GPU_framebuffer_texture_detach(fx->dof_near_coc_final_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_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_blurred_buffer, 0, NULL);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ /* *unbind/detach */
+ GPU_depth_texture_mode(fx->depth_buffer, true, false);
+ GPU_texture_unbind(fx->depth_buffer);
+
+ GPU_texture_unbind(fx->dof_near_coc_final_buffer);
+ GPU_framebuffer_texture_detach(fx->dof_near_coc_blurred_buffer);
+
+ dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor);
+
+ numslots = 0;
+ }
+
+ /* third pass, calculate near coc */
+ {
+ int near_coc_downsampled, near_coc_blurred;
+
+ near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass3, "colorbuffer");
+ near_coc_blurred = GPU_shader_get_uniform(dof_shader_pass3, "blurredcolorbuffer");
+
+ GPU_shader_bind(dof_shader_pass3);
+
+ GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass3, near_coc_downsampled, fx->dof_near_coc_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);
+
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL);
+
+ 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);
+
+ /* unbinding here restores the size to the original */
+ GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer);
+
+ numslots = 0;
+ }
+
+ /* 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)};
+
+ near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass4, "colorbuffer");
+ invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass4, "invrendertargetdim");
+
+ GPU_shader_bind(dof_shader_pass4);
+
+ 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_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ /* disable bindings */
+ GPU_texture_unbind(fx->dof_near_coc_final_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);
+
+ numslots = 0;
+ }
+
+ /* 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_depth_texture_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_depth_texture_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;
+ }
+ }
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ GPU_shader_unbind();
+
+ return true;
+}
+
+void GPU_fx_compositor_init_dof_settings(GPUDOFSettings *fx_dof)
+{
+ fx_dof->fstop = 128.0f;
+ fx_dof->focal_length = 1.0f;
+ fx_dof->focus_distance = 1.0f;
+ fx_dof->sensor = 1.0f;
+}
+
+void GPU_fx_compositor_init_ssao_settings(GPUSSAOSettings *fx_ssao)
+{
+ fx_ssao->factor = 1.0f;
+ fx_ssao->distance_max = 0.2f;
+ fx_ssao->attenuation = 1.0f;
+ fx_ssao->samples = 4;
+}
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index a6b711fd556..4d1a9770c78 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -47,6 +47,7 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
+#include "GPU_compositing.h"
#include "GPU_simple_shader.h"
#include "intern/gpu_extensions_private.h"
@@ -78,10 +79,17 @@ extern char datatoc_gpu_shader_vsm_store_vert_glsl[];
extern char datatoc_gpu_shader_vsm_store_frag_glsl[];
extern char datatoc_gpu_shader_sep_gaussian_blur_vert_glsl[];
extern char datatoc_gpu_shader_sep_gaussian_blur_frag_glsl[];
+extern char datatoc_gpu_shader_fx_vert_glsl[];
+extern char datatoc_gpu_shader_fx_ssao_frag_glsl[];
+extern char datatoc_gpu_shader_fx_dof_frag_glsl[];
+extern char datatoc_gpu_shader_fx_dof_vert_glsl[];
+extern char datatoc_gpu_shader_fx_lib_glsl[];
typedef struct GPUShaders {
GPUShader *vsm_store;
GPUShader *sep_gaussian_blur;
+ /* cache for shader fx. Those can exist in combinations so store them here */
+ GPUShader *fx_shaders[MAX_FX_SHADERS * 2];
} GPUShaders;
static struct GPUGlobal {
@@ -364,7 +372,9 @@ static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, i
MEM_freeN(pixels);
}
-static GPUTexture *GPU_texture_create_nD(int w, int h, int n, float *fpixels, int depth, char err_out[256])
+static GPUTexture *GPU_texture_create_nD(
+ int w, int h, int n, float *fpixels, int depth, GPUHDRType hdr_type, int components,
+ char err_out[256])
{
GPUTexture *tex;
GLenum type, format, internalformat;
@@ -411,12 +421,45 @@ static GPUTexture *GPU_texture_create_nD(int w, int h, int n, float *fpixels, in
internalformat = GL_DEPTH_COMPONENT;
}
else {
- type = GL_UNSIGNED_BYTE;
- format = GL_RGBA;
- internalformat = GL_RGBA8;
+ type = GL_FLOAT;
+
+ if (components == 4) {
+ format = GL_RGBA;
+ switch (hdr_type) {
+ case GPU_HDR_NONE:
+ internalformat = GL_RGBA8;
+ break;
+ case GPU_HDR_HALF_FLOAT:
+ internalformat = GL_RGBA16F;
+ break;
+ case GPU_HDR_FULL_FLOAT:
+ internalformat = GL_RGBA32F;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (components == 2) {
+ format = GL_RG;
+ switch (hdr_type) {
+ case GPU_HDR_NONE:
+ internalformat = GL_RG8;
+ break;
+ case GPU_HDR_HALF_FLOAT:
+ internalformat = GL_RG16F;
+ break;
+ case GPU_HDR_FULL_FLOAT:
+ internalformat = GL_RG32F;
+ break;
+ default:
+ break;
+ }
+ }
- if (fpixels)
+ if (fpixels && hdr_type == GPU_HDR_NONE) {
+ type = GL_UNSIGNED_BYTE;
pixels = GPU_texture_convert_pixels(w*h, fpixels);
+ }
}
if (tex->target == GL_TEXTURE_1D) {
@@ -651,7 +694,7 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
GPUTexture *GPU_texture_create_1D(int w, float *fpixels, char err_out[256])
{
- GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, err_out);
+ GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, err_out);
if (tex)
GPU_texture_unbind(tex);
@@ -659,9 +702,9 @@ GPUTexture *GPU_texture_create_1D(int w, float *fpixels, char err_out[256])
return tex;
}
-GPUTexture *GPU_texture_create_2D(int w, int h, float *fpixels, char err_out[256])
+GPUTexture *GPU_texture_create_2D(int w, int h, float *fpixels, GPUHDRType hdr, char err_out[256])
{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, err_out);
+ GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, err_out);
if (tex)
GPU_texture_unbind(tex);
@@ -671,7 +714,7 @@ GPUTexture *GPU_texture_create_2D(int w, int h, float *fpixels, char err_out[256
GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256])
{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, err_out);
+ GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, err_out);
if (tex)
GPU_texture_unbind(tex);
@@ -684,13 +727,45 @@ 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 *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, err_out);
+ GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, err_out);
if (tex) {
/* Now we tweak some of the settings */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, size, size, 0, GL_RG, GL_FLOAT, NULL);
+
+ GPU_texture_unbind(tex);
+ }
+
+ return tex;
+}
+
+GPUTexture *GPU_texture_create_2D_procedural(int w, int h, float *pixels, 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);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ GPU_texture_unbind(tex);
+ }
+
+ return tex;
+}
+
+GPUTexture *GPU_texture_create_1D_procedural(int w, float *pixels, char err_out[256])
+{
+ GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, err_out);
+
+ if (tex) {
+ /* Now we tweak some of the settings */
+ glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
GPU_texture_unbind(tex);
}
@@ -702,7 +777,7 @@ void GPU_invalid_tex_init(void)
{
float color[4] = {1.0f, 0.0f, 1.0f, 1.0};
GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL);
- GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, NULL);
+ GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, GPU_HDR_NONE, NULL);
GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, 4, color);
}
@@ -792,6 +867,45 @@ void GPU_texture_unbind(GPUTexture *tex)
GPU_print_error("Post Texture Unbind");
}
+void GPU_depth_texture_mode(GPUTexture *tex, bool compare, bool use_filter)
+{
+ GLenum arbnumber;
+
+ if (tex->number >= GG.maxtextures) {
+ GPU_print_error("Not enough texture slots.");
+ return;
+ }
+
+ if (!tex->depth) {
+ GPU_print_error("Not a depth texture.");
+ return;
+ }
+
+ if (tex->number == -1)
+ return;
+
+ GPU_print_error("Pre Texture Unbind");
+
+ 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 (use_filter) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
+ else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+ if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
+
+ GPU_print_error("Post Texture Unbind");
+}
+
void GPU_texture_free(GPUTexture *tex)
{
tex->refcount--;
@@ -982,13 +1096,23 @@ void GPU_texture_bind_as_framebuffer(GPUTexture *tex)
glPushMatrix();
}
-void GPU_framebuffer_slot_bind(GPUFrameBuffer *fb, int slot)
+void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot)
{
+ int numslots = 0, i;
+ GLenum attachments[4];
+
if (!fb->colortex[slot]) {
fprintf(stderr, "Error, framebuffer slot empty!");
return;
}
-
+
+ for (i = 0 ; i < 4; i++) {
+ if (fb->colortex[i]) {
+ attachments[numslots] = GL_COLOR_ATTACHMENT0_EXT + i;
+ numslots++;
+ }
+ }
+
/* push attributes */
glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT);
glDisable(GL_SCISSOR_TEST);
@@ -997,7 +1121,7 @@ void GPU_framebuffer_slot_bind(GPUFrameBuffer *fb, int slot)
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
/* last bound prevails here, better allow explicit control here too */
- glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
+ glDrawBuffers(numslots, attachments);
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
/* push matrices and set default viewport and matrix */
@@ -1023,6 +1147,18 @@ void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUS
glPopAttrib();
}
+void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot)
+{
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+ /* last bound prevails here, better allow explicit control here too */
+ glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
+
+ /* push matrices and set default viewport and matrix */
+ glViewport(0, 0, fb->colortex[slot]->w, fb->colortex[slot]->h);
+ GG.currentfb = fb->object;
+ GG.currentfb = fb->object;
+}
bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256])
{
@@ -1045,7 +1181,6 @@ bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256])
return true;
}
-
void GPU_framebuffer_free(GPUFrameBuffer *fb)
{
int i;
@@ -1080,8 +1215,8 @@ void GPU_framebuffer_restore(void)
void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex)
{
- float scaleh[2] = {1.0f/GPU_texture_opengl_width(blurtex), 0.0f};
- float scalev[2] = {0.0f, 1.0f/GPU_texture_opengl_height(tex)};
+ const float scaleh[2] = {1.0f / GPU_texture_opengl_width(blurtex), 0.0f};
+ const float scalev[2] = {0.0f, 1.0f / GPU_texture_opengl_height(tex)};
GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR);
int scale_uniform, texture_source_uniform;
@@ -1103,7 +1238,7 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b
GG.currentfb = blurfb->object;
GPU_shader_bind(blur_shader);
- GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float *)scaleh);
+ GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scaleh);
GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex);
glViewport(0, 0, GPU_texture_opengl_width(blurtex), GPU_texture_opengl_height(blurtex));
@@ -1126,7 +1261,7 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b
glTexCoord2d(1, 1); glVertex2f(-1, -1);
glTexCoord2d(0, 1); glVertex2f(1, -1);
glEnd();
-
+
/* Blurring vertically */
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
@@ -1135,7 +1270,7 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b
GG.currentfb = fb->object;
glViewport(0, 0, GPU_texture_opengl_width(tex), GPU_texture_opengl_height(tex));
- GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float *)scalev);
+ GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scalev);
GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex);
GPU_texture_bind(blurtex, 0);
@@ -1180,7 +1315,7 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256])
return NULL;
}
- ofs->color = GPU_texture_create_2D(width, height, NULL, err_out);
+ ofs->color = GPU_texture_create_2D(width, height, NULL, GPU_HDR_NONE, err_out);
if (!ofs->color) {
GPU_offscreen_free(ofs);
return NULL;
@@ -1214,15 +1349,20 @@ void GPU_offscreen_free(GPUOffScreen *ofs)
MEM_freeN(ofs);
}
-void GPU_offscreen_bind(GPUOffScreen *ofs)
+void GPU_offscreen_bind(GPUOffScreen *ofs, bool save)
{
glDisable(GL_SCISSOR_TEST);
- GPU_texture_bind_as_framebuffer(ofs->color);
+ if (save)
+ GPU_framebuffer_slots_bind(ofs->fb, 0);
+ else {
+ GPU_framebuffer_bind_no_save(ofs->fb, 0);
+ }
}
-void GPU_offscreen_unbind(GPUOffScreen *ofs)
+void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore)
{
- GPU_framebuffer_texture_unbind(ofs->fb, ofs->color);
+ if (restore)
+ GPU_framebuffer_texture_unbind(ofs->fb, ofs->color);
GPU_framebuffer_restore();
glEnable(GL_SCISSOR_TEST);
}
@@ -1250,6 +1390,7 @@ struct GPUShader {
GLhandleARB fragment; /* handle for fragment shader */
GLhandleARB lib; /* handle for libment shader */
int totattrib; /* total number of attributes */
+ int uniforms; /* required uniforms */
};
static void shader_print_errors(const char *task, char *log, const char **code, int totcode)
@@ -1494,7 +1635,7 @@ int GPU_shader_get_uniform(GPUShader *shader, const char *name)
return glGetUniformLocationARB(shader->object, name);
}
-void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, float *value)
+void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, const float *value)
{
if (location == -1)
return;
@@ -1588,8 +1729,64 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
return retval;
}
+#define MAX_DEFINES 100
+
+GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp)
+{
+ int offset;
+ char defines[MAX_DEFINES] = "";
+ /* avoid shaders out of range */
+ if (effects >= MAX_FX_SHADERS)
+ return NULL;
+
+ offset = 2 * effects;
+
+ if (persp) {
+ offset += 1;
+ strcat(defines, "#define PERSP_MATRIX\n");
+ }
+
+ if (!GG.shaders.fx_shaders[offset]) {
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ break;
+ }
+ }
+
+ return GG.shaders.fx_shaders[offset];
+}
+
+
void GPU_shader_free_builtin_shaders(void)
{
+ int i;
+
if (GG.shaders.vsm_store) {
MEM_freeN(GG.shaders.vsm_store);
GG.shaders.vsm_store = NULL;
@@ -1599,6 +1796,13 @@ void GPU_shader_free_builtin_shaders(void)
MEM_freeN(GG.shaders.sep_gaussian_blur);
GG.shaders.sep_gaussian_blur = NULL;
}
+
+ for (i = 0; i < 2 * MAX_FX_SHADERS; i++) {
+ if (GG.shaders.fx_shaders[i]) {
+ MEM_freeN(GG.shaders.fx_shaders[i]);
+ GG.shaders.fx_shaders[i] = NULL;
+ }
+ }
}
#if 0
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl
new file mode 100644
index 00000000000..d52ab2243fe
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl
@@ -0,0 +1,206 @@
+/* amount of offset to move one pixel left-right.
+ * In second pass some dimensions are zero to control verical/horizontal convolution */
+uniform vec2 invrendertargetdim;
+// color buffer
+uniform sampler2D colorbuffer;
+//blurred color buffer for DOF effect
+uniform sampler2D blurredcolorbuffer;
+// slightly blurred buffer
+uniform sampler2D mblurredcolorbuffer;
+// depth buffer
+uniform sampler2D depthbuffer;
+
+// 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];
+
+// coordinates on framebuffer in normalized (0.0-1.0) uv space
+varying vec4 uvcoordsvar;
+
+/* color texture coordinates, offset by a small amount */
+varying vec2 color_uv1;
+varying vec2 color_uv2;
+
+varying vec2 depth_uv1;
+varying vec2 depth_uv2;
+varying vec2 depth_uv3;
+varying vec2 depth_uv4;
+
+
+float calculate_far_coc(in float zdepth)
+{
+ float coc = dof_params.x * max(1.0 - dof_params.y / zdepth, 0.0);
+
+ /* multiply by 1.0 / sensor size to get the normalized size */
+ return coc * dof_params.z;
+}
+
+/* near coc only! when distance is nearer than focus plane first term is bigger than one */
+vec4 calculate_near_coc(in vec4 zdepth)
+{
+ vec4 coc = dof_params.x * max(vec4(dof_params.y) / zdepth - vec4(1.0), vec4(0.0));
+
+ /* multiply by 1.0 / sensor size to get the normalized size */
+ return coc * dof_params.z;
+}
+
+/* first pass blurs the color buffer heavily and gets the near coc only.
+ * There are many texture accesses here but they are done on a
+ * lower resolution image so overall bandwidth is not a concern */
+void first_pass()
+{
+ vec4 depth;
+ vec4 zdepth;
+ vec4 coc;
+ float final_coc;
+
+ /* amount to add to uvs so that they move one row further */
+ vec2 offset_row[3];
+ offset_row[0] = vec2(0.0, invrendertargetdim.y);
+ offset_row[1] = 2.0 * offset_row[0];
+ offset_row[2] = 3.0 * offset_row[0];
+
+ /* heavily blur the image */
+ vec4 color = texture2D(colorbuffer, color_uv1);
+ color += texture2D(colorbuffer, color_uv1 + offset_row[1]);
+ color += texture2D(colorbuffer, color_uv2);
+ color += texture2D(colorbuffer, color_uv2 + offset_row[1]);
+ color /= 4.0;
+
+ depth.r = texture2D(depthbuffer, depth_uv1).r;
+ depth.g = texture2D(depthbuffer, depth_uv2).r;
+ depth.b = texture2D(depthbuffer, depth_uv3).r;
+ depth.a = texture2D(depthbuffer, depth_uv4).r;
+
+ zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth);
+ coc = calculate_near_coc(zdepth);
+
+ depth.r = texture2D(depthbuffer, depth_uv1 + offset_row[0]).r;
+ depth.g = texture2D(depthbuffer, depth_uv2 + offset_row[0]).r;
+ depth.b = texture2D(depthbuffer, depth_uv3 + offset_row[0]).r;
+ depth.a = texture2D(depthbuffer, depth_uv4 + offset_row[0]).r;
+
+ zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth);
+ coc = max(calculate_near_coc(zdepth), coc);
+
+ depth.r = texture2D(depthbuffer, depth_uv1 + offset_row[1]).r;
+ depth.g = texture2D(depthbuffer, depth_uv2 + offset_row[1]).r;
+ depth.b = texture2D(depthbuffer, depth_uv3 + offset_row[1]).r;
+ depth.a = texture2D(depthbuffer, depth_uv4 + offset_row[1]).r;
+
+ zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth);
+ coc = max(calculate_near_coc(zdepth), coc);
+
+ depth.r = texture2D(depthbuffer, depth_uv1 + offset_row[2]).r;
+ depth.g = texture2D(depthbuffer, depth_uv2 + offset_row[2]).r;
+ depth.b = texture2D(depthbuffer, depth_uv3 + offset_row[2]).r;
+ depth.a = texture2D(depthbuffer, depth_uv4 + offset_row[2]).r;
+
+ zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth);
+ coc = max(calculate_near_coc(zdepth), coc);
+
+ final_coc = max(max(coc.x, coc.y), max(coc.z, coc.w));
+ gl_FragColor = vec4(color.rgb, final_coc);
+}
+
+/* second pass, gaussian blur the downsampled image */
+void second_pass()
+{
+ vec4 depth = vec4(texture2D(depthbuffer, uvcoordsvar.xy).r);
+
+ /* clever sampling to sample 2 pixels at once. Of course it's not real gaussian sampling this way */
+ vec4 color = texture2D(colorbuffer, uvcoordsvar.xy) * 0.3125;
+ color += texture2D(colorbuffer, uvcoordsvar.xy + invrendertargetdim) * 0.234375;
+ color += texture2D(colorbuffer, uvcoordsvar.xy + 2.5 * invrendertargetdim) * 0.09375;
+ color += texture2D(colorbuffer, uvcoordsvar.xy + 4.5 * invrendertargetdim) * 0.015625;
+ color += texture2D(colorbuffer, uvcoordsvar.xy -invrendertargetdim) * 0.234375;
+ color += texture2D(colorbuffer, uvcoordsvar.xy -2.5 * invrendertargetdim) * 0.09375;
+ color += texture2D(colorbuffer, uvcoordsvar.xy -4.5 * invrendertargetdim) * 0.015625;
+
+ gl_FragColor = color;
+}
+
+
+/* third pass, calculate the final coc from blurred and unblurred images */
+void third_pass()
+{
+ vec4 color = texture2D(colorbuffer, uvcoordsvar.xy);
+ vec4 color_blurred = texture2D(blurredcolorbuffer, uvcoordsvar.xy);
+ float coc = 2.0 * max(color_blurred.a, color.a); - color.a;
+ gl_FragColor = vec4(color.rgb, coc);
+}
+
+
+/* fourth pass, blur the final coc once to get rid of discontinuities */
+void fourth_pass()
+{
+ vec4 color = texture2D(colorbuffer, uvcoordsvar.xz);
+ color += texture2D(colorbuffer, uvcoordsvar.yz);
+ color += texture2D(colorbuffer, uvcoordsvar.xw);
+ color += texture2D(colorbuffer, uvcoordsvar.yw);
+
+ gl_FragColor = color / 4.0;
+}
+
+vec4 small_sample_blur(in sampler2D colorbuffer, in vec2 uv, in vec4 color)
+{
+ float weight = 1.0/ 17.0;
+ vec4 result = weight * color;
+ weight *= 4.0;
+
+ result += weight * texture2D(colorbuffer, uv + color_uv1.xy);
+ result += weight * texture2D(colorbuffer, uv - color_uv1.xy);
+ result += weight * texture2D(colorbuffer, uv + color_uv1.yx);
+ result += weight * texture2D(colorbuffer, uv - color_uv1.yx);
+
+ return result;
+}
+
+
+/* fourth pass, just visualize the third pass contents */
+void fifth_pass()
+{
+ vec4 factors;
+ vec4 color_orig = texture2D(colorbuffer, uvcoordsvar.xy);
+ vec4 highblurred = texture2D(blurredcolorbuffer, uvcoordsvar.xy);
+ vec4 mediumblurred = texture2D(mblurredcolorbuffer, uvcoordsvar.xy);
+ vec4 smallblurred = small_sample_blur(colorbuffer, uvcoordsvar.xy, color_orig);
+ float depth = texture2D(depthbuffer, uvcoordsvar.xy).r;
+
+ float zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), vec4(depth)).r;
+ float coc_far = clamp(calculate_far_coc(zdepth), 0.0, 1.0);
+
+ /* calculate final coc here */
+ float coc = max(max(coc_far, mediumblurred.a), 0.0);
+
+ float width = 2.5;
+ float radius = 0.2;
+
+ factors.x = 1.0 - clamp(width * coc, 0.0, 1.0);
+ factors.y = 1.0 - clamp(abs(width * (coc - 2.0 * radius)), 0.0, 1.0);
+ factors.z = 1.0 - clamp(abs(width * (coc - 3.0 * radius)), 0.0, 1.0);
+ factors.w = 1.0 - clamp(abs(width * (coc - 4.0 * radius)), 0.0, 1.0);
+ /* blend! */
+ vec4 color = factors.x * color_orig + factors.y * smallblurred + factors.z * mediumblurred + factors.w * highblurred;
+
+ color /= dot(factors, vec4(1.0));
+ gl_FragColor = vec4(color.rgb, 1.0);
+}
+
+
+void main()
+{
+#ifdef FIRST_PASS
+ first_pass();
+#elif defined(SECOND_PASS)
+ second_pass();
+#elif defined(THIRD_PASS)
+ third_pass();
+#elif defined(FOURTH_PASS)
+ fourth_pass();
+#elif defined(FIFTH_PASS)
+ fifth_pass();
+#endif
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl
new file mode 100644
index 00000000000..a2ef990c4e8
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl
@@ -0,0 +1,68 @@
+uniform vec2 invrendertargetdim;
+
+//texture coordinates for framebuffer read
+varying vec4 uvcoordsvar;
+
+/* color texture coordinates, offset by a small amount */
+varying vec2 color_uv1;
+varying vec2 color_uv2;
+
+varying vec2 depth_uv1;
+varying vec2 depth_uv2;
+varying vec2 depth_uv3;
+varying vec2 depth_uv4;
+
+//very simple shader for gull screen FX, just pass values on
+
+void vert_generic()
+{
+ uvcoordsvar = gl_MultiTexCoord0;
+ gl_Position = gl_Vertex;
+}
+
+void vert_dof_first_pass()
+{
+ /* we offset the texture coordinates by 1.5 pixel,
+ * then we reuse that to sample the surrounding pixels */
+ color_uv1 = gl_MultiTexCoord0.xy + vec2(-1.5, -1.5) * invrendertargetdim;
+ color_uv2 = gl_MultiTexCoord0.xy + vec2(0.5, -1.5) * invrendertargetdim;
+
+ depth_uv1 = gl_MultiTexCoord0.xy + vec2(-1.5, -1.5) * invrendertargetdim;
+ depth_uv2 = gl_MultiTexCoord0.xy + vec2(-0.5, -1.5) * invrendertargetdim;
+ depth_uv3 = gl_MultiTexCoord0.xy + vec2(0.5, -1.5) * invrendertargetdim;
+ depth_uv4 = gl_MultiTexCoord0.xy + vec2(1.5, -1.5) * invrendertargetdim;
+
+ gl_Position = gl_Vertex;
+}
+
+void vert_dof_fourth_pass()
+{
+ vec4 halfpixel = vec4(-0.5, 0.5, -0.5, 0.5);
+ uvcoordsvar = gl_MultiTexCoord0.xxyy + halfpixel * vec4(invrendertargetdim.x,
+ invrendertargetdim.x, invrendertargetdim.y, invrendertargetdim.y);
+
+ gl_Position = gl_Vertex;
+}
+
+void vert_dof_fifth_pass()
+{
+ vec4 halfpixel = vec4(-0.5, 0.5, -0.5, 0.5);
+ color_uv1 = vec2(0.5, 1.5) * invrendertargetdim;
+
+ uvcoordsvar = gl_MultiTexCoord0;
+ gl_Position = gl_Vertex;
+}
+
+void main()
+{
+#ifdef FIRST_PASS
+ vert_dof_first_pass();
+#elif defined(FOURTH_PASS)
+ vert_dof_fourth_pass();
+#elif defined(FIFTH_PASS)
+ vert_dof_fifth_pass();
+#else
+ vert_generic();
+#endif
+}
+
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl b/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl
new file mode 100644
index 00000000000..6c4bf3bb7a0
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl
@@ -0,0 +1,47 @@
+vec3 calculate_view_space_normal(in vec3 viewposition)
+{
+ vec3 normal = cross(normalize(dFdx(viewposition)),
+ normalize(dFdy(viewposition)));
+ normalize(normal);
+ return normal;
+}
+
+/* simple depth reconstruction, see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer
+ * we change the factors from the article to fit the OpennGL model. */
+#ifdef PERSP_MATRIX
+
+/* perspective camera code */
+
+vec3 get_view_space_from_depth(in vec2 uvcoords, in vec3 viewvec_origin, in vec3 viewvec_diff, in float depth)
+{
+ float d = 2.0 * depth - 1.0;
+
+ float zview = -gl_ProjectionMatrix[3][2] / (d + gl_ProjectionMatrix[2][2]);
+
+ return zview * (viewvec_origin + vec3(uvcoords, 0.0) * viewvec_diff);
+}
+
+vec4 get_view_space_z_from_depth(in vec4 near, in vec4 range, in vec4 depth)
+{
+ vec4 d = 2.0 * depth - vec4(1.0);
+
+ /* return positive value, so sign differs! */
+ return vec4(gl_ProjectionMatrix[3][2]) / (d + vec4(gl_ProjectionMatrix[2][2]));
+}
+
+#else
+/* orthographic camera code */
+
+vec3 get_view_space_from_depth(in vec2 uvcoords, in vec3 viewvec_origin, in vec3 viewvec_diff, in float depth)
+{
+ vec3 offset = vec3(uvcoords, depth);
+
+ return vec3(viewvec_origin + offset * viewvec_diff);
+}
+
+vec4 get_view_space_z_from_depth(in vec4 near, in vec4 range, in vec4 depth)
+{
+ return -(near + depth * range);
+}
+
+#endif
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
new file mode 100644
index 00000000000..b33fda92a46
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
@@ -0,0 +1,82 @@
+// color buffer
+uniform sampler2D colorbuffer;
+
+// jitter texture for ssao
+uniform sampler2D jitter_tex;
+
+// concentric sample texture for ssao
+uniform sampler1D ssao_concentric_tex;
+
+// depth buffer
+uniform sampler2D depthbuffer;
+// coordinates on framebuffer in normalized (0.0-1.0) uv space
+varying vec4 uvcoordsvar;
+
+/* ssao_params.x : pixel scale for the ssao radious */
+/* ssao_params.y : factor for the ssao darkening */
+uniform vec4 ssao_params;
+uniform vec4 ssao_sample_params;
+uniform vec4 ssao_color;
+
+/* store the view space vectors for the corners of the view frustum here.
+ * It helps to quickly reconstruct view space vectors by using uv coordinates,
+ * see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
+uniform vec4 viewvecs[3];
+
+float calculate_ssao_factor(float depth)
+{
+ /* take the normalized ray direction here */
+ vec2 rotX = texture2D(jitter_tex, uvcoordsvar.xy * ssao_sample_params.zw).rg;
+ vec2 rotY = vec2(-rotX.y, rotX.x);
+
+ /* occlusion is zero in full depth */
+ if (depth == 1.0)
+ return 0.0;
+
+ vec3 position = get_view_space_from_depth(uvcoordsvar.xy, viewvecs[0].xyz, viewvecs[1].xyz, depth);
+ vec3 normal = calculate_view_space_normal(position);
+
+ // find the offset in screen space by multiplying a point in camera space at the depth of the point by the projection matrix.
+ vec2 offset;
+ float homcoord = gl_ProjectionMatrix[2][3] * position.z + gl_ProjectionMatrix[3][3];
+ offset.x = gl_ProjectionMatrix[0][0] * ssao_params.x / homcoord;
+ offset.y = gl_ProjectionMatrix[1][1] * ssao_params.x / homcoord;
+ /* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */
+ offset *= 0.5;
+
+ float factor = 0.0;
+ int x;
+ int num_samples = int(ssao_sample_params.x);
+
+ for (x = 0; x < num_samples; x++) {
+ vec2 dir_sample = texture1D(ssao_concentric_tex, (float(x) + 0.5) / ssao_sample_params.x).rg;
+
+ /* rotate with random direction to get jittered result */
+ vec2 dir_jittered = vec2(dot(dir_sample, rotX), dot(dir_sample, rotY));
+
+ vec2 uvcoords = uvcoordsvar.xy + dir_jittered * offset;
+
+ float depth_new = texture2D(depthbuffer, uvcoords).r;
+ if (depth_new != 1.0) {
+ vec3 pos_new = get_view_space_from_depth(uvcoords, viewvecs[0].xyz, viewvecs[1].xyz, depth_new);
+ vec3 dir = pos_new - position;
+ float len = length(dir);
+ float f = dot(dir, normal);
+
+ /* use minor bias here to avoid self shadowing */
+ if (f > 0.05 * len + 0.0001)
+ factor += f * 1.0/(len * (1.0 + len * len * ssao_params.z));
+ }
+ }
+
+ factor /= ssao_sample_params.x;
+
+ return clamp(factor * ssao_params.y, 0.0, 1.0);
+}
+
+void main()
+{
+ float depth = texture2D(depthbuffer, uvcoordsvar.xy).r;
+ vec4 color = mix(texture2D(colorbuffer, uvcoordsvar.xy), ssao_color, calculate_ssao_factor(depth));
+ gl_FragColor = vec4(color.rgb, 1.0);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_vert.glsl
new file mode 100644
index 00000000000..5194e414520
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fx_vert.glsl
@@ -0,0 +1,9 @@
+varying vec4 uvcoordsvar;
+
+//very simple shader for full screen FX, just pass values on
+
+void main()
+{
+ uvcoordsvar = gl_MultiTexCoord0;
+ gl_Position = gl_Vertex;
+}