doxygen: add newline after \file
[blender.git] / source / blender / draw / engines / workbench / workbench_effect_taa.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Copyright 2016, Blender Foundation.
17  */
18
19 /** \file
20  * \ingroup draw_engine
21  */
22
23
24 #include "workbench_private.h"
25 #include "BLI_jitter_2d.h"
26
27 static struct {
28         struct GPUShader *effect_taa_sh;
29         float jitter_8[8][2];
30         float jitter_16[16][2];
31         float jitter_32[32][2];
32 } e_data = {NULL};
33
34 extern char datatoc_workbench_effect_taa_frag_glsl[];
35
36
37 static void workbench_taa_jitter_init_order(float (*table)[2], int num)
38 {
39         BLI_jitter_init(table, num);
40
41         /* find closest element to center */
42         int closest_index = 0;
43         float closest_squared_distance = 1.0f;
44
45         for (int index = 0; index < num; index++) {
46                 const float squared_dist = SQUARE(table[index][0]) + SQUARE(table[index][1]);
47                 if (squared_dist < closest_squared_distance) {
48                         closest_squared_distance = squared_dist;
49                         closest_index = index;
50                 }
51         }
52
53         /* move jitter table so that closest sample is in center */
54         for (int index = 0; index < num; index++) {
55                 sub_v2_v2(table[index], table[closest_index]);
56                 mul_v2_fl(table[index], 2.0f);
57         }
58
59         /* swap center sample to the start of the table */
60         if (closest_index != 0) {
61                 swap_v2_v2(table[0], table[closest_index]);
62         }
63
64         /* sort list based on furtest distance with previous */
65         for (int i = 0; i < num - 2; i++) {
66                 float f_squared_dist = 0.0;
67                 int f_index = i;
68                 for (int j = i + 1; j < num; j++) {
69                         const float squared_dist = SQUARE(table[i][0] - table[j][0]) + SQUARE(table[i][1] - table[j][1]);
70                         if (squared_dist > f_squared_dist) {
71                                 f_squared_dist = squared_dist;
72                                 f_index = j;
73                         }
74                 }
75                 swap_v2_v2(table[i + 1], table[f_index]);
76         }
77 }
78
79
80 static void workbench_taa_jitter_init(void)
81 {
82         workbench_taa_jitter_init_order(e_data.jitter_8, 8);
83         workbench_taa_jitter_init_order(e_data.jitter_16, 16);
84         workbench_taa_jitter_init_order(e_data.jitter_32, 32);
85 }
86
87 int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata)
88 {
89         WORKBENCH_StorageList *stl = vedata->stl;
90         WORKBENCH_PrivateData *wpd = stl->g_data;
91         int result = 1;
92         if (TAA_ENABLED(wpd)) {
93                 if (DRW_state_is_image_render()) {
94                         const Scene *scene = DRW_context_state_get()->scene;
95                         result = (scene->r.mode & R_OSA) ? scene->r.osa : 1;
96                 }
97                 else if (IN_RANGE_INCL(
98                             wpd->preferences->gpu_viewport_quality,
99                             GPU_VIEWPORT_QUALITY_TAA8, GPU_VIEWPORT_QUALITY_TAA16))
100                 {
101                         result = 8;
102                 }
103                 else if (IN_RANGE_INCL(
104                             wpd->preferences->gpu_viewport_quality,
105                             GPU_VIEWPORT_QUALITY_TAA16, GPU_VIEWPORT_QUALITY_TAA32))
106                 {
107                         result = 16;
108                 }
109                 else {
110                         result = 32;
111                 }
112         }
113         return result;
114 }
115
116 void workbench_taa_engine_init(WORKBENCH_Data *vedata)
117 {
118         WORKBENCH_EffectInfo *effect_info = vedata->stl->effects;
119         const DRWContextState *draw_ctx = DRW_context_state_get();
120         RegionView3D *rv3d = draw_ctx->rv3d;
121
122         if (e_data.effect_taa_sh == NULL) {
123                 e_data.effect_taa_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_taa_frag_glsl, NULL);
124                 workbench_taa_jitter_init();
125         }
126
127         /* reset complete drawing when navigating. */
128         if (effect_info->jitter_index != 0) {
129                 if (rv3d && rv3d->rflag & RV3D_NAVIGATING) {
130                         effect_info->jitter_index = 0;
131                 }
132         }
133
134         if (effect_info->view_updated) {
135                 effect_info->jitter_index = 0;
136                 effect_info->view_updated = false;
137         }
138
139         {
140                 float view[4][4];
141                 float win[4][4];
142                 DRW_viewport_matrix_get(view, DRW_MAT_VIEW);
143                 DRW_viewport_matrix_get(win, DRW_MAT_WIN);
144                 mul_m4_m4m4(effect_info->curr_mat, view, win);
145                 if (!equals_m4m4(effect_info->curr_mat, effect_info->last_mat)) {
146                         effect_info->jitter_index = 0;
147                 }
148         }
149 }
150
151 void workbench_taa_engine_free(void)
152 {
153         DRW_SHADER_FREE_SAFE(e_data.effect_taa_sh);
154 }
155
156
157 DRWPass *workbench_taa_create_pass(WORKBENCH_Data *vedata, GPUTexture **color_buffer_tx)
158 {
159         WORKBENCH_StorageList *stl = vedata->stl;
160         WORKBENCH_TextureList *txl = vedata->txl;
161         WORKBENCH_EffectInfo *effect_info = stl->effects;
162         WORKBENCH_FramebufferList *fbl = vedata->fbl;
163         WORKBENCH_PrivateData *wpd = stl->g_data;
164         /*
165          * jitter_index is not updated yet. This will be done in during draw phase.
166          * so for now it is inversed.
167          */
168         int previous_jitter_index = effect_info->jitter_index;
169
170         {
171                 const eGPUTextureFormat hist_buffer_format = DRW_state_is_image_render() ? GPU_RGBA16F : GPU_RGBA8;
172                 DRW_texture_ensure_fullscreen_2D(&txl->history_buffer_tx, hist_buffer_format, 0);
173                 DRW_texture_ensure_fullscreen_2D(&txl->depth_buffer_tx, GPU_DEPTH24_STENCIL8, 0);
174         }
175
176         {
177                 GPU_framebuffer_ensure_config(&fbl->effect_taa_fb, {
178                         GPU_ATTACHMENT_NONE,
179                         GPU_ATTACHMENT_TEXTURE(txl->history_buffer_tx),
180                 });
181                 GPU_framebuffer_ensure_config(&fbl->depth_buffer_fb, {
182                         GPU_ATTACHMENT_TEXTURE(txl->depth_buffer_tx),
183                 });
184         }
185
186
187         DRWPass *pass = DRW_pass_create("Effect TAA", DRW_STATE_WRITE_COLOR);
188         DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_taa_sh, pass);
189         DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", color_buffer_tx);
190         DRW_shgroup_uniform_texture_ref(grp, "historyBuffer", &txl->history_buffer_tx);
191         DRW_shgroup_uniform_float(grp, "mixFactor", &effect_info->taa_mix_factor, 1);
192         DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
193
194         /*
195          * Set the offset for the cavity shader so every iteration different
196          * samples will be selected
197          */
198         wpd->ssao_params[3] = previous_jitter_index;
199
200         return pass;
201 }
202
203 void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata)
204 {
205         WORKBENCH_StorageList *stl = vedata->stl;
206         WORKBENCH_EffectInfo *effect_info = stl->effects;
207         const float *viewport_size = DRW_viewport_size_get();
208         int num_samples = 8;
209         float (*samples)[2];
210         float mix_factor;
211
212         num_samples = workbench_taa_calculate_num_iterations(vedata);
213         switch (num_samples) {
214                 default:
215                 case 8:
216                         samples = e_data.jitter_8;
217                         break;
218                 case 16:
219                         samples = e_data.jitter_16;
220                         break;
221                 case 32:
222                         samples = e_data.jitter_32;
223                         break;
224         }
225
226         mix_factor = 1.0f / (effect_info->jitter_index + 1);
227
228         const int bitmask = num_samples - 1;
229         const int jitter_index = effect_info->jitter_index;
230         const float *transform_offset = samples[jitter_index];
231         effect_info->jitter_index = (jitter_index + 1) & bitmask;
232
233         /* construct new matrices from transform delta */
234         float viewmat[4][4];
235         float persmat[4][4];
236         DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW);
237         DRW_viewport_matrix_get(persmat, DRW_MAT_PERS);
238         DRW_viewport_matrix_get(effect_info->override_winmat, DRW_MAT_WIN);
239
240         window_translate_m4(
241                 effect_info->override_winmat, persmat,
242                 transform_offset[0] / viewport_size[0],
243                 transform_offset[1] / viewport_size[1]);
244
245         mul_m4_m4m4(effect_info->override_persmat, effect_info->override_winmat, viewmat);
246         invert_m4_m4(effect_info->override_persinv, effect_info->override_persmat);
247         invert_m4_m4(effect_info->override_wininv, effect_info->override_winmat);
248
249         DRW_viewport_matrix_override_set(effect_info->override_persmat, DRW_MAT_PERS);
250         DRW_viewport_matrix_override_set(effect_info->override_persinv, DRW_MAT_PERSINV);
251         DRW_viewport_matrix_override_set(effect_info->override_winmat,  DRW_MAT_WIN);
252         DRW_viewport_matrix_override_set(effect_info->override_wininv,  DRW_MAT_WININV);
253
254         /* weight the mix factor by the jitter index */
255         effect_info->taa_mix_factor = mix_factor;
256 }
257
258 void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata)
259 {
260         /*
261          * If first frame than the offset is 0.0 and its depth is the depth buffer to use
262          * for the rest of the draw engines. We store it in a persistent buffer.
263          *
264          * If it is not the first frame we copy the persistent buffer back to the
265          * default depth buffer
266          */
267         const WORKBENCH_StorageList *stl = vedata->stl;
268         const WORKBENCH_FramebufferList *fbl = vedata->fbl;
269         const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
270         WORKBENCH_EffectInfo *effect_info = stl->effects;
271
272         if (effect_info->jitter_index == 1) {
273                 GPU_framebuffer_blit(dfbl->depth_only_fb, 0, fbl->depth_buffer_fb, 0, GPU_DEPTH_BIT);
274         }
275         else {
276                 GPU_framebuffer_blit(fbl->depth_buffer_fb, 0, dfbl->depth_only_fb, 0, GPU_DEPTH_BIT);
277         }
278
279         GPU_framebuffer_blit(dfbl->color_only_fb, 0, fbl->effect_taa_fb, 0, GPU_COLOR_BIT);
280
281         if (!DRW_state_is_image_render()) {
282                 DRW_viewport_matrix_override_unset_all();
283         }
284
285         copy_m4_m4(effect_info->last_mat, effect_info->curr_mat);
286         if (effect_info->jitter_index != 0 && !DRW_state_is_image_render()) {
287                 DRW_viewport_request_redraw();
288         }
289 }
290
291 void workbench_taa_view_updated(WORKBENCH_Data *vedata)
292 {
293         WORKBENCH_StorageList *stl = vedata->stl;
294         if (stl) {
295                 WORKBENCH_EffectInfo *effect_info = stl->effects;
296                 if (effect_info) {
297                         effect_info->view_updated = true;
298                 }
299         }
300 }