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/draw/engines/workbench/workbench_effect_aa.c')
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_aa.c337
1 files changed, 292 insertions, 45 deletions
diff --git a/source/blender/draw/engines/workbench/workbench_effect_aa.c b/source/blender/draw/engines/workbench/workbench_effect_aa.c
index 482cb81917f..94deacf27d5 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_aa.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_aa.c
@@ -13,7 +13,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * Copyright 2016, Blender Foundation.
+ * Copyright 2020, Blender Foundation.
*/
/** \file
@@ -22,71 +22,318 @@
#include "ED_screen.h"
-#include "draw_color_management.h"
+#include "BLI_jitter_2d.h"
+
+#include "smaa_textures.h"
#include "workbench_private.h"
-void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx)
+static struct {
+ bool init;
+ float jitter_5[5][2];
+ float jitter_8[8][2];
+ float jitter_11[11][2];
+ float jitter_16[16][2];
+ float jitter_32[32][2];
+} e_data = {false};
+
+static void workbench_taa_jitter_init_order(float (*table)[2], int num)
{
- WORKBENCH_StorageList *stl = vedata->stl;
- WORKBENCH_PrivateData *wpd = stl->g_data;
- WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_EffectInfo *effect_info = stl->effects;
+ BLI_jitter_init(table, num);
+
+ /* find closest element to center */
+ int closest_index = 0;
+ float closest_squared_distance = 1.0f;
+
+ for (int index = 0; index < num; index++) {
+ const float squared_dist = SQUARE(table[index][0]) + SQUARE(table[index][1]);
+ if (squared_dist < closest_squared_distance) {
+ closest_squared_distance = squared_dist;
+ closest_index = index;
+ }
+ }
+
+ /* move jitter table so that closest sample is in center */
+ for (int index = 0; index < num; index++) {
+ sub_v2_v2(table[index], table[closest_index]);
+ mul_v2_fl(table[index], 2.0f);
+ }
- if (workbench_is_taa_enabled(wpd)) {
- psl->effect_aa_pass = workbench_taa_create_pass(vedata, tx);
+ /* swap center sample to the start of the table */
+ if (closest_index != 0) {
+ swap_v2_v2(table[0], table[closest_index]);
}
- else if (workbench_is_fxaa_enabled(wpd)) {
- psl->effect_aa_pass = workbench_fxaa_create_pass(tx);
- effect_info->jitter_index = 0;
+
+ /* sort list based on furtest distance with previous */
+ for (int i = 0; i < num - 2; i++) {
+ float f_squared_dist = 0.0;
+ int f_index = i;
+ for (int j = i + 1; j < num; j++) {
+ const float squared_dist = SQUARE(table[i][0] - table[j][0]) +
+ SQUARE(table[i][1] - table[j][1]);
+ if (squared_dist > f_squared_dist) {
+ f_squared_dist = squared_dist;
+ f_index = j;
+ }
+ }
+ swap_v2_v2(table[i + 1], table[f_index]);
+ }
+}
+
+static void workbench_taa_jitter_init(void)
+{
+ if (e_data.init == false) {
+ workbench_taa_jitter_init_order(e_data.jitter_5, 5);
+ workbench_taa_jitter_init_order(e_data.jitter_8, 8);
+ workbench_taa_jitter_init_order(e_data.jitter_11, 11);
+ workbench_taa_jitter_init_order(e_data.jitter_16, 16);
+ workbench_taa_jitter_init_order(e_data.jitter_32, 32);
+ }
+}
+
+BLI_INLINE bool workbench_taa_enabled(WORKBENCH_PrivateData *wpd)
+{
+ if (DRW_state_is_image_render()) {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ if (draw_ctx->v3d) {
+ return draw_ctx->scene->display.viewport_aa > SCE_DISPLAY_AA_FXAA;
+ }
+ else {
+ return draw_ctx->scene->display.render_aa > SCE_DISPLAY_AA_FXAA;
+ }
+ }
+ else {
+ return !(IS_NAVIGATING(wpd) || wpd->is_playback) &&
+ wpd->preferences->viewport_aa > SCE_DISPLAY_AA_FXAA;
+ }
+}
+
+int workbench_aa_sample_count_get(WORKBENCH_PrivateData *wpd)
+{
+ const Scene *scene = DRW_context_state_get()->scene;
+ if (workbench_taa_enabled(wpd)) {
+ if (DRW_state_is_image_render()) {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ if (draw_ctx->v3d) {
+ return scene->display.viewport_aa;
+ }
+ else {
+ return scene->display.render_aa;
+ }
+ }
+ else {
+ return wpd->preferences->viewport_aa;
+ }
+ }
+ else {
+ /* when no TAA is disabled return 0 to render a single sample
+ * see `workbench_render.c` */
+ return 0;
+ }
+}
+
+void workbench_aa_engine_init(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_TextureList *txl = vedata->txl;
+ WORKBENCH_PrivateData *wpd = vedata->stl->g_data;
+ DrawEngineType *owner = (DrawEngineType *)&workbench_aa_engine_init;
+
+ if (wpd->taa_sample_len > 0) {
+ workbench_taa_jitter_init();
+
+ DRW_texture_ensure_fullscreen_2d(&txl->history_buffer_tx, GPU_RGBA16F, 0);
+ DRW_texture_ensure_fullscreen_2d(&txl->depth_buffer_tx, GPU_DEPTH24_STENCIL8, 0);
+
+ wpd->smaa_edge_tx = DRW_texture_pool_query_fullscreen(GPU_RG8, owner);
+ wpd->smaa_weight_tx = DRW_texture_pool_query_fullscreen(GPU_RGBA8, owner);
+
+ GPU_framebuffer_ensure_config(&fbl->antialiasing_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(txl->depth_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(txl->history_buffer_tx),
+ });
+
+ GPU_framebuffer_ensure_config(&fbl->smaa_edge_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->smaa_edge_tx),
+ });
+
+ GPU_framebuffer_ensure_config(&fbl->smaa_weight_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->smaa_weight_tx),
+ });
+
+ /* TODO could be shared for all viewports. */
+ if (txl->smaa_search_tx == NULL) {
+ txl->smaa_search_tx = GPU_texture_create_nD(SEARCHTEX_WIDTH,
+ SEARCHTEX_HEIGHT,
+ 0,
+ 2,
+ searchTexBytes,
+ GPU_R8,
+ GPU_DATA_UNSIGNED_BYTE,
+ 0,
+ false,
+ NULL);
+
+ txl->smaa_area_tx = GPU_texture_create_nD(AREATEX_WIDTH,
+ AREATEX_HEIGHT,
+ 0,
+ 2,
+ areaTexBytes,
+ GPU_RG8,
+ GPU_DATA_UNSIGNED_BYTE,
+ 0,
+ false,
+ NULL);
+
+ GPU_texture_bind(txl->smaa_search_tx, 0);
+ GPU_texture_filter_mode(txl->smaa_search_tx, true);
+ GPU_texture_unbind(txl->smaa_search_tx);
+
+ GPU_texture_bind(txl->smaa_area_tx, 0);
+ GPU_texture_filter_mode(txl->smaa_area_tx, true);
+ GPU_texture_unbind(txl->smaa_area_tx);
+ }
}
else {
- psl->effect_aa_pass = NULL;
- effect_info->jitter_index = 0;
+ /* Cleanup */
+ DRW_TEXTURE_FREE_SAFE(txl->history_buffer_tx);
+ DRW_TEXTURE_FREE_SAFE(txl->depth_buffer_tx);
+ DRW_TEXTURE_FREE_SAFE(txl->smaa_search_tx);
+ DRW_TEXTURE_FREE_SAFE(txl->smaa_area_tx);
}
}
-static void workspace_aa_draw_transform(GPUTexture *tx, WORKBENCH_PrivateData *UNUSED(wpd))
+void workbench_aa_cache_init(WORKBENCH_Data *vedata)
{
- DRW_transform_none(tx);
+ WORKBENCH_TextureList *txl = vedata->txl;
+ WORKBENCH_PrivateData *wpd = vedata->stl->g_data;
+ WORKBENCH_PassList *psl = vedata->psl;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ DRWShadingGroup *grp = NULL;
+
+ if (wpd->taa_sample_len > 0) {
+ return;
+ }
+
+ {
+ DRW_PASS_CREATE(psl->aa_accum_pass, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL);
+
+ GPUShader *shader = workbench_shader_antialiasing_accumulation_get();
+ grp = DRW_shgroup_create(shader, psl->aa_accum_pass);
+ DRW_shgroup_uniform_texture(grp, "colorBuffer", dtxl->color);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+
+ const float *size = DRW_viewport_size_get();
+ const float *sizeinv = DRW_viewport_invert_size_get();
+ float metrics[4] = {sizeinv[0], sizeinv[1], size[0], size[1]};
+
+ {
+ /* Stage 1: Edge detection. */
+ DRW_PASS_CREATE(psl->aa_edge_pass, DRW_STATE_WRITE_COLOR);
+
+ GPUShader *sh = workbench_shader_antialiasing_get(0);
+ grp = DRW_shgroup_create(sh, psl->aa_edge_pass);
+ DRW_shgroup_uniform_texture(grp, "colorTex", dtxl->color);
+ DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+
+ DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ {
+ /* Stage 2: Blend Weight/Coord. */
+ DRW_PASS_CREATE(psl->aa_weight_pass, DRW_STATE_WRITE_COLOR);
+
+ GPUShader *sh = workbench_shader_antialiasing_get(1);
+ grp = DRW_shgroup_create(sh, psl->aa_weight_pass);
+ DRW_shgroup_uniform_texture(grp, "edgesTex", wpd->smaa_edge_tx);
+ DRW_shgroup_uniform_texture(grp, "areaTex", txl->smaa_area_tx);
+ DRW_shgroup_uniform_texture(grp, "searchTex", txl->smaa_search_tx);
+ DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+
+ DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ {
+ /* Stage 3: Resolve. */
+ DRW_PASS_CREATE(psl->aa_resolve_pass, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
+
+ GPUShader *sh = workbench_shader_antialiasing_get(2);
+ grp = DRW_shgroup_create(sh, psl->aa_resolve_pass);
+ DRW_shgroup_uniform_texture(grp, "blendTex", wpd->smaa_weight_tx);
+ DRW_shgroup_uniform_texture(grp, "colorTex", txl->history_buffer_tx);
+ DRW_shgroup_uniform_float(grp, "mixFactor", &wpd->smaa_mix_factor, 1);
+ DRW_shgroup_uniform_float_copy(grp, "invTaaSampleCount", wpd->taa_sample_inv);
+ DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
}
-void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx)
+void workbench_aa_draw_pass(WORKBENCH_Data *vedata)
{
WORKBENCH_StorageList *stl = vedata->stl;
WORKBENCH_PrivateData *wpd = stl->g_data;
WORKBENCH_FramebufferList *fbl = vedata->fbl;
WORKBENCH_PassList *psl = vedata->psl;
- WORKBENCH_EffectInfo *effect_info = stl->effects;
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- if (workbench_is_fxaa_enabled(wpd)) {
- GPU_framebuffer_bind(fbl->effect_fb);
- workspace_aa_draw_transform(tx, wpd);
- GPU_framebuffer_bind(dfbl->color_only_fb);
- DRW_draw_pass(psl->effect_aa_pass);
- }
- else if (workbench_is_taa_enabled(wpd)) {
- /*
- * when drawing the first TAA frame, we transform directly to the
- * color_only_fb as the TAA shader is just performing a direct copy.
- * the workbench_taa_draw_screen_end will fill the history buffer
- * for the other iterations.
- */
- if (effect_info->jitter_index == 1) {
- GPU_framebuffer_bind(dfbl->color_only_fb);
- workspace_aa_draw_transform(tx, wpd);
- }
- else {
- GPU_framebuffer_bind(fbl->effect_fb);
- workspace_aa_draw_transform(tx, wpd);
- GPU_framebuffer_bind(dfbl->color_only_fb);
- DRW_draw_pass(psl->effect_aa_pass);
- }
- workbench_taa_draw_scene_end(vedata);
+
+ if (wpd->taa_sample_len == 0) {
+ /* AA disabled. */
+ return;
}
- else {
- GPU_framebuffer_bind(dfbl->color_only_fb);
- workspace_aa_draw_transform(tx, wpd);
+
+ /* After a certain point SMAA is no longer necessary. */
+ wpd->smaa_mix_factor = 1.0f - clamp_f(wpd->taa_sample / 4.0f, 0.0f, 1.0f);
+ wpd->taa_sample_inv = 1.0f / wpd->taa_sample;
+
+ /**
+ * We always do SMAA on top of TAA accumulation, unless the number of samples of TAA is already
+ * high. This ensure a smoother transition.
+ * If TAA accumulation is finished, we only blit the result.
+ */
+
+ if (wpd->taa_sample == 1) {
+ /* In playback mode, we are sure the next redraw will not use the same viewmatrix.
+ * In this case no need to save the depth buffer. */
+ eGPUFrameBufferBits bits = GPU_COLOR_BIT | (!wpd->is_playback ? GPU_DEPTH_BIT : 0);
+ GPU_framebuffer_blit(dfbl->default_fb, 0, fbl->antialiasing_fb, 0, bits);
+ }
+ else if (wpd->taa_sample < wpd->taa_sample_len) {
+ /* Accumulate result to the TAA buffer. */
+ GPU_framebuffer_bind(fbl->antialiasing_fb);
+ DRW_draw_pass(psl->aa_accum_pass);
+ }
+
+ if (wpd->taa_sample == wpd->taa_sample_len) {
+ /* TAA accumulation has finish. Just copy the result back */
+ eGPUFrameBufferBits bits = GPU_COLOR_BIT | GPU_DEPTH_BIT;
+ GPU_framebuffer_blit(fbl->antialiasing_fb, 0, dfbl->default_fb, 0, bits);
+ return;
+ }
+ else if (wpd->taa_sample > 1) {
+ /* Copy back the saved depth buffer for correct overlays. */
+ GPU_framebuffer_blit(fbl->antialiasing_fb, 0, dfbl->default_fb, 0, GPU_DEPTH_BIT);
+ }
+
+ if (wpd->smaa_mix_factor > 0.0f) {
+ GPU_framebuffer_bind(fbl->smaa_edge_fb);
+ DRW_draw_pass(psl->aa_edge_pass);
+
+ GPU_framebuffer_bind(fbl->smaa_weight_fb);
+ DRW_draw_pass(psl->aa_weight_pass);
+ }
+
+ GPU_framebuffer_bind(dfbl->default_fb);
+ DRW_draw_pass(psl->aa_resolve_pass);
+
+ if (!DRW_state_is_image_render() && wpd->taa_sample < wpd->taa_sample_len) {
+ DRW_viewport_request_redraw();
}
}