diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2021-08-25 09:55:50 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2021-08-25 09:55:50 +0300 |
commit | df05fae12695d00a092bdb694786310bface6cbe (patch) | |
tree | fa7ee49ca3413064f053efc6a80b501b6ff4ad36 | |
parent | 4793154d0d8f881134a0f662921646d4f04e546c (diff) | |
parent | 820d50d3cbf3a3995ca5a4051c82e8ee24805796 (diff) |
Merge branch 'master' into temp-runtime-node-def
282 files changed, 6265 insertions, 1843 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a555876d21..47712f0ac1e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1598,8 +1598,7 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_UNUSED_PARAMETER -Wunused-parameter) ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_ALL -Wall) - # Designated initializer is a C++20 feature & breaks MSVC build. Dropping MSVC 2019 or - # updating to C++20 allows removing this. + # Using C++20 features while having C++17 as the project language isn't allowed by MSVC. ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_CXX20_DESIGNATOR -Wc++20-designator) ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_AUTOLOGICAL_COMPARE -Wno-tautological-compare) diff --git a/build_files/config/pipeline_config.yaml b/build_files/config/pipeline_config.yaml index 611df59caec..5d1a24a30f1 100644 --- a/build_files/config/pipeline_config.yaml +++ b/build_files/config/pipeline_config.yaml @@ -51,9 +51,9 @@ buildbot: gcc: version: '9.0.0' cuda10: - version: '10.1.0' + version: '10.1.243' cuda11: - version: '11.4.0' + version: '11.4.1' optix: version: '7.1.0' cmake: diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index 3cf75b338dc..f6824f31b7b 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -424,7 +424,7 @@ static inline void set_enum(PointerRNA &ptr, const char *name, const string &ide static inline string get_string(PointerRNA &ptr, const char *name) { char cstrbuf[1024]; - char *cstr = RNA_string_get_alloc(&ptr, name, cstrbuf, sizeof(cstrbuf)); + char *cstr = RNA_string_get_alloc(&ptr, name, cstrbuf, sizeof(cstrbuf), NULL); string str(cstr); if (cstr != cstrbuf) MEM_freeN(cstr); diff --git a/intern/cycles/kernel/closure/bsdf_principled_diffuse.h b/intern/cycles/kernel/closure/bsdf_principled_diffuse.h index 43646aaeb5b..d5d012068ff 100644 --- a/intern/cycles/kernel/closure/bsdf_principled_diffuse.h +++ b/intern/cycles/kernel/closure/bsdf_principled_diffuse.h @@ -36,10 +36,10 @@ static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledDiffuseBsdf), ccl_device float3 calculate_principled_diffuse_brdf( const PrincipledDiffuseBsdf *bsdf, float3 N, float3 V, float3 L, float3 H, float *pdf) { - float NdotL = max(dot(N, L), 0.0f); - float NdotV = max(dot(N, V), 0.0f); + float NdotL = dot(N, L); + float NdotV = dot(N, V); - if (NdotL < 0 || NdotV < 0) { + if (NdotL <= 0 || NdotV <= 0) { *pdf = 0.0f; return make_float3(0.0f, 0.0f, 0.0f); } diff --git a/intern/cycles/kernel/geom/geom_triangle.h b/intern/cycles/kernel/geom/geom_triangle.h index 1e7fbd9c7fb..ff7909ca425 100644 --- a/intern/cycles/kernel/geom/geom_triangle.h +++ b/intern/cycles/kernel/geom/geom_triangle.h @@ -107,8 +107,8 @@ triangle_smooth_normal(KernelGlobals *kg, float3 Ng, int prim, float u, float v) return is_zero(N) ? Ng : N; } -ccl_device_inline float3 -triangle_smooth_normal_unnormalized(KernelGlobals *kg, float3 Ng, int prim, float u, float v) +ccl_device_inline float3 triangle_smooth_normal_unnormalized( + KernelGlobals *kg, ShaderData *sd, float3 Ng, int prim, float u, float v) { /* load triangle vertices */ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); @@ -116,6 +116,13 @@ triangle_smooth_normal_unnormalized(KernelGlobals *kg, float3 Ng, int prim, floa float3 n1 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y)); float3 n2 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z)); + /* ensure that the normals are in object space */ + if (sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED) { + object_inverse_normal_transform(kg, sd, &n0); + object_inverse_normal_transform(kg, sd, &n1); + object_inverse_normal_transform(kg, sd, &n2); + } + float3 N = (1.0f - u - v) * n2 + u * n0 + v * n1; return is_zero(N) ? Ng : N; diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h index fec6a2cc27f..46600551cc4 100644 --- a/intern/cycles/kernel/svm/svm_tex_coord.h +++ b/intern/cycles/kernel/svm/svm_tex_coord.h @@ -289,7 +289,7 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st float3 normal; if (sd->shader & SHADER_SMOOTH_NORMAL) { - normal = triangle_smooth_normal_unnormalized(kg, sd->Ng, sd->prim, sd->u, sd->v); + normal = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v); } else { normal = sd->Ng; diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index d9538930f33..55f60329a97 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -1909,19 +1909,19 @@ def km_node_editor(params): ("node.clipboard_paste", {"type": 'V', "value": 'PRESS', "ctrl": True}, None), ("node.viewer_border", {"type": 'B', "value": 'PRESS', "ctrl": True}, None), ("node.clear_viewer_border", {"type": 'B', "value": 'PRESS', "ctrl": True, "alt": True}, None), - ("node.translate_attach", {"type": 'G', "value": 'PRESS'}, None), - ("node.translate_attach", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None), - ("node.translate_attach", {"type": params.select_tweak, "value": 'ANY'}, None), - ("transform.translate", {"type": 'G', "value": 'PRESS'}, None), + ("node.translate_attach", {"type": 'G', "value": 'PRESS'}, {"properties": [("TRANSFORM_OT_translate", [("view2d_edge_pan", True)])]}), + ("node.translate_attach", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, {"properties": [("TRANSFORM_OT_translate", [("view2d_edge_pan", True)])]}), + ("node.translate_attach", {"type": params.select_tweak, "value": 'ANY'}, {"properties": [("TRANSFORM_OT_translate", [("view2d_edge_pan", True)])]}), + ("transform.translate", {"type": 'G', "value": 'PRESS'}, {"properties": [("view2d_edge_pan", True)]}), ("transform.translate", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, - {"properties": [("release_confirm", True)]}), + {"properties": [("release_confirm", True), ("view2d_edge_pan", True)]}), ("transform.translate", {"type": params.select_tweak, "value": 'ANY'}, - {"properties": [("release_confirm", True)]}), + {"properties": [("release_confirm", True), ("view2d_edge_pan", True)]}), ("transform.rotate", {"type": 'R', "value": 'PRESS'}, None), ("transform.resize", {"type": 'S', "value": 'PRESS'}, None), - ("node.move_detach_links", {"type": 'D', "value": 'PRESS', "alt": True}, None), - ("node.move_detach_links_release", {"type": params.action_tweak, "value": 'ANY', "alt": True}, None), - ("node.move_detach_links", {"type": params.select_tweak, "value": 'ANY', "alt": True}, None), + ("node.move_detach_links", {"type": 'D', "value": 'PRESS', "alt": True}, {"properties": [("TRANSFORM_OT_translate", [("view2d_edge_pan", True)])]}), + ("node.move_detach_links_release", {"type": params.action_tweak, "value": 'ANY', "alt": True}, {"properties": [("NODE_OT_translate_attach", [("TRANSFORM_OT_translate", [("view2d_edge_pan", True)])])]}), + ("node.move_detach_links", {"type": params.select_tweak, "value": 'ANY', "alt": True}, {"properties": [("TRANSFORM_OT_translate", [("view2d_edge_pan", True)])]}), ("wm.context_toggle", {"type": 'TAB', "value": 'PRESS', "shift": True}, {"properties": [("data_path", 'tool_settings.use_snap')]}), ("wm.context_menu_enum", {"type": 'TAB', "value": 'PRESS', "shift": True, "ctrl": True}, diff --git a/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py b/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py index 247a1ec342e..05ecac4d70c 100644 --- a/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py +++ b/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py @@ -29,9 +29,28 @@ def update_factory_startup_screens(): params.use_filter_folder = True +def update_factory_startup_ffmpeg_preset(): + preset = "H264_in_MP4" + preset_filepath = bpy.utils.preset_find(preset, preset_path="ffmpeg") + if not preset_filepath: + print("Preset %r not found" % preset) + + for scene in bpy.data.scenes: + render = scene.render + render.image_settings.file_format = 'FFMPEG' + + if preset_filepath: + bpy.ops.script.python_file_run({"scene": scene}, filepath=preset_filepath) + + render.ffmpeg.audio_codec = 'AAC' + render.ffmpeg.audio_bitrate = 256 + + @persistent def load_handler(_): update_factory_startup_screens() + if bpy.app.build_options.codec_ffmpeg: + update_factory_startup_ffmpeg_preset() def register(): diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 003f2f223ea..708701c4804 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -997,7 +997,6 @@ class USERPREF_PT_theme_text_style(ThemePanel, CenterAlignMixIn, Panel): flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) col = flow.column() - col.row().prop(font_style, "font_kerning_style", expand=True) col.prop(font_style, "points") col = flow.column(align=True) diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index eb3f9805240..4de7e704a7e 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -98,13 +98,13 @@ void BLF_batch_draw_flush(void); void BLF_batch_draw_end(void); /* Draw the string using the current font. */ -void BLF_draw_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) +void BLF_draw_ex(int fontid, const char *str, size_t str_len, struct ResultBLF *r_info) ATTR_NONNULL(2); -void BLF_draw(int fontid, const char *str, size_t len) ATTR_NONNULL(2); -void BLF_draw_ascii_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) +void BLF_draw(int fontid, const char *str, size_t str_len) ATTR_NONNULL(2); +void BLF_draw_ascii_ex(int fontid, const char *str, size_t str_len, struct ResultBLF *r_info) ATTR_NONNULL(2); -void BLF_draw_ascii(int fontid, const char *str, size_t len) ATTR_NONNULL(2); -int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) ATTR_NONNULL(2); +void BLF_draw_ascii(int fontid, const char *str, size_t str_len) ATTR_NONNULL(2); +int BLF_draw_mono(int fontid, const char *str, size_t str_len, int cwidth) ATTR_NONNULL(2); typedef bool (*BLF_GlyphBoundsFn)(const char *str, const size_t str_step_ofs, @@ -116,43 +116,45 @@ typedef bool (*BLF_GlyphBoundsFn)(const char *str, void BLF_boundbox_foreach_glyph_ex(int fontid, const char *str, - size_t len, + size_t str_len, BLF_GlyphBoundsFn user_fn, void *user_data, struct ResultBLF *r_info) ATTR_NONNULL(2); void BLF_boundbox_foreach_glyph(int fontid, const char *str, - size_t len, + size_t str_len, BLF_GlyphBoundsFn user_fn, void *user_data) ATTR_NONNULL(2); /* Get the string byte offset that fits within a given width */ -size_t BLF_width_to_strlen(int fontid, const char *str, size_t len, float width, float *r_width) - ATTR_NONNULL(2); +size_t BLF_width_to_strlen( + int fontid, const char *str, size_t str_len, float width, float *r_width) ATTR_NONNULL(2); /* Same as BLF_width_to_strlen but search from the string end */ -size_t BLF_width_to_rstrlen(int fontid, const char *str, size_t len, float width, float *r_width) - ATTR_NONNULL(2); +size_t BLF_width_to_rstrlen( + int fontid, const char *str, size_t str_len, float width, float *r_width) ATTR_NONNULL(2); /* This function return the bounding box of the string * and are not multiplied by the aspect. */ void BLF_boundbox_ex(int fontid, const char *str, - size_t len, + size_t str_len, struct rctf *box, struct ResultBLF *r_info) ATTR_NONNULL(2); -void BLF_boundbox(int fontid, const char *str, size_t len, struct rctf *box) ATTR_NONNULL(); +void BLF_boundbox(int fontid, const char *str, size_t str_len, struct rctf *box) ATTR_NONNULL(); /* The next both function return the width and height * of the string, using the current font and both value * are multiplied by the aspect of the font. */ -float BLF_width_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) +float BLF_width_ex(int fontid, const char *str, size_t str_len, struct ResultBLF *r_info) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2); -float BLF_width(int fontid, const char *str, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -float BLF_height_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) +float BLF_width(int fontid, const char *str, size_t str_len) ATTR_WARN_UNUSED_RESULT + ATTR_NONNULL(); +float BLF_height_ex(int fontid, const char *str, size_t str_len, struct ResultBLF *r_info) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2); -float BLF_height(int fontid, const char *str, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +float BLF_height(int fontid, const char *str, size_t str_len) ATTR_WARN_UNUSED_RESULT + ATTR_NONNULL(); /* Return dimensions of the font without any sample text. */ int BLF_height_max(int fontid) ATTR_WARN_UNUSED_RESULT; @@ -163,8 +165,8 @@ float BLF_ascender(int fontid) ATTR_WARN_UNUSED_RESULT; /* The following function return the width and height of the string, but * just in one call, so avoid extra freetype2 stuff. */ -void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_width, float *r_height) - ATTR_NONNULL(); +void BLF_width_and_height( + int fontid, const char *str, size_t str_len, float *r_width, float *r_height) ATTR_NONNULL(); /* For fixed width fonts only, returns the width of a * character. @@ -221,9 +223,9 @@ void BLF_buffer_col(int fontid, const float rgba[4]) ATTR_NONNULL(2); /* Draw the string into the buffer, this function draw in both buffer, * float and unsigned char _BUT_ it's not necessary set both buffer, NULL is valid here. */ -void BLF_draw_buffer_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) +void BLF_draw_buffer_ex(int fontid, const char *str, size_t str_len, struct ResultBLF *r_info) ATTR_NONNULL(2); -void BLF_draw_buffer(int fontid, const char *str, size_t len) ATTR_NONNULL(2); +void BLF_draw_buffer(int fontid, const char *str, size_t str_len) ATTR_NONNULL(2); /* Add a path to the font dir paths. */ void BLF_dir_add(const char *path) ATTR_NONNULL(); @@ -254,8 +256,9 @@ void BLF_default_dpi(int dpi); void BLF_default_set(int fontid); int BLF_default(void); /* get default font ID so we can pass it to other functions */ /* Draw the string using the default font, size and dpi. */ -void BLF_draw_default(float x, float y, float z, const char *str, size_t len) ATTR_NONNULL(); -void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t len) ATTR_NONNULL(); +void BLF_draw_default(float x, float y, float z, const char *str, size_t str_len) ATTR_NONNULL(); +void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t str_len) + ATTR_NONNULL(); /* Set size and DPI, and return default font ID. */ int BLF_set_default(void); diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 2f9eb0753ac..86d67c80fd4 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -521,7 +521,7 @@ static void blf_draw_gl__end(FontBLF *font) } } -void BLF_draw_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) +void BLF_draw_ex(int fontid, const char *str, const size_t str_len, struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); @@ -530,27 +530,27 @@ void BLF_draw_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_in if (font) { blf_draw_gl__start(font); if (font->flags & BLF_WORD_WRAP) { - blf_font_draw__wrap(font, str, len, r_info); + blf_font_draw__wrap(font, str, str_len, r_info); } else { - blf_font_draw(font, str, len, r_info); + blf_font_draw(font, str, str_len, r_info); } blf_draw_gl__end(font); } } -void BLF_draw(int fontid, const char *str, size_t len) +void BLF_draw(int fontid, const char *str, const size_t str_len) { - if (len == 0 || str[0] == '\0') { + if (str_len == 0 || str[0] == '\0') { return; } /* Avoid bgl usage to corrupt BLF drawing. */ GPU_bgl_end(); - BLF_draw_ex(fontid, str, len, NULL); + BLF_draw_ex(fontid, str, str_len, NULL); } -void BLF_draw_ascii_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) +void BLF_draw_ascii_ex(int fontid, const char *str, const size_t str_len, struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); @@ -560,27 +560,27 @@ void BLF_draw_ascii_ex(int fontid, const char *str, size_t len, struct ResultBLF blf_draw_gl__start(font); if (font->flags & BLF_WORD_WRAP) { /* Use non-ASCII draw function for word-wrap. */ - blf_font_draw__wrap(font, str, len, r_info); + blf_font_draw__wrap(font, str, str_len, r_info); } else { - blf_font_draw_ascii(font, str, len, r_info); + blf_font_draw_ascii(font, str, str_len, r_info); } blf_draw_gl__end(font); } } -void BLF_draw_ascii(int fontid, const char *str, size_t len) +void BLF_draw_ascii(int fontid, const char *str, const size_t str_len) { - if (len == 0 || str[0] == '\0') { + if (str_len == 0 || str[0] == '\0') { return; } - BLF_draw_ascii_ex(fontid, str, len, NULL); + BLF_draw_ascii_ex(fontid, str, str_len, NULL); } -int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) +int BLF_draw_mono(int fontid, const char *str, const size_t str_len, int cwidth) { - if (len == 0 || str[0] == '\0') { + if (str_len == 0 || str[0] == '\0') { return 0; } @@ -589,7 +589,7 @@ int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) if (font) { blf_draw_gl__start(font); - columns = blf_font_draw_mono(font, str, len, cwidth); + columns = blf_font_draw_mono(font, str, str_len, cwidth); blf_draw_gl__end(font); } @@ -606,7 +606,7 @@ int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) */ void BLF_boundbox_foreach_glyph_ex(int fontid, const char *str, - size_t len, + size_t str_len, BLF_GlyphBoundsFn user_fn, void *user_data, struct ResultBLF *r_info) @@ -621,25 +621,26 @@ void BLF_boundbox_foreach_glyph_ex(int fontid, BLI_assert(0); } else { - blf_font_boundbox_foreach_glyph(font, str, len, user_fn, user_data, r_info); + blf_font_boundbox_foreach_glyph(font, str, str_len, user_fn, user_data, r_info); } } } void BLF_boundbox_foreach_glyph( - int fontid, const char *str, size_t len, BLF_GlyphBoundsFn user_fn, void *user_data) + int fontid, const char *str, const size_t str_len, BLF_GlyphBoundsFn user_fn, void *user_data) { - BLF_boundbox_foreach_glyph_ex(fontid, str, len, user_fn, user_data, NULL); + BLF_boundbox_foreach_glyph_ex(fontid, str, str_len, user_fn, user_data, NULL); } -size_t BLF_width_to_strlen(int fontid, const char *str, size_t len, float width, float *r_width) +size_t BLF_width_to_strlen( + int fontid, const char *str, const size_t str_len, float width, float *r_width) { FontBLF *font = blf_get(fontid); if (font) { const float xa = (font->flags & BLF_ASPECT) ? font->aspect[0] : 1.0f; size_t ret; - ret = blf_font_width_to_strlen(font, str, len, width / xa, r_width); + ret = blf_font_width_to_strlen(font, str, str_len, width / xa, r_width); if (r_width) { *r_width *= xa; } @@ -652,14 +653,15 @@ size_t BLF_width_to_strlen(int fontid, const char *str, size_t len, float width, return 0; } -size_t BLF_width_to_rstrlen(int fontid, const char *str, size_t len, float width, float *r_width) +size_t BLF_width_to_rstrlen( + int fontid, const char *str, const size_t str_len, float width, float *r_width) { FontBLF *font = blf_get(fontid); if (font) { const float xa = (font->flags & BLF_ASPECT) ? font->aspect[0] : 1.0f; size_t ret; - ret = blf_font_width_to_rstrlen(font, str, len, width / xa, r_width); + ret = blf_font_width_to_rstrlen(font, str, str_len, width / xa, r_width); if (r_width) { *r_width *= xa; } @@ -673,7 +675,7 @@ size_t BLF_width_to_rstrlen(int fontid, const char *str, size_t len, float width } void BLF_boundbox_ex( - int fontid, const char *str, size_t len, rctf *r_box, struct ResultBLF *r_info) + int fontid, const char *str, const size_t str_len, rctf *r_box, struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); @@ -681,47 +683,48 @@ void BLF_boundbox_ex( if (font) { if (font->flags & BLF_WORD_WRAP) { - blf_font_boundbox__wrap(font, str, len, r_box, r_info); + blf_font_boundbox__wrap(font, str, str_len, r_box, r_info); } else { - blf_font_boundbox(font, str, len, r_box, r_info); + blf_font_boundbox(font, str, str_len, r_box, r_info); } } } -void BLF_boundbox(int fontid, const char *str, size_t len, rctf *r_box) +void BLF_boundbox(int fontid, const char *str, const size_t str_len, rctf *r_box) { - BLF_boundbox_ex(fontid, str, len, r_box, NULL); + BLF_boundbox_ex(fontid, str, str_len, r_box, NULL); } -void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_width, float *r_height) +void BLF_width_and_height( + int fontid, const char *str, const size_t str_len, float *r_width, float *r_height) { FontBLF *font = blf_get(fontid); if (font) { - blf_font_width_and_height(font, str, len, r_width, r_height, NULL); + blf_font_width_and_height(font, str, str_len, r_width, r_height, NULL); } else { *r_width = *r_height = 0.0f; } } -float BLF_width_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) +float BLF_width_ex(int fontid, const char *str, const size_t str_len, struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); BLF_RESULT_CHECK_INIT(r_info); if (font) { - return blf_font_width(font, str, len, r_info); + return blf_font_width(font, str, str_len, r_info); } return 0.0f; } -float BLF_width(int fontid, const char *str, size_t len) +float BLF_width(int fontid, const char *str, const size_t str_len) { - return BLF_width_ex(fontid, str, len, NULL); + return BLF_width_ex(fontid, str, str_len, NULL); } float BLF_fixed_width(int fontid) @@ -735,22 +738,22 @@ float BLF_fixed_width(int fontid) return 0.0f; } -float BLF_height_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) +float BLF_height_ex(int fontid, const char *str, const size_t str_len, struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); BLF_RESULT_CHECK_INIT(r_info); if (font) { - return blf_font_height(font, str, len, r_info); + return blf_font_height(font, str, str_len, r_info); } return 0.0f; } -float BLF_height(int fontid, const char *str, size_t len) +float BLF_height(int fontid, const char *str, const size_t str_len) { - return BLF_height_ex(fontid, str, len, NULL); + return BLF_height_ex(fontid, str, str_len, NULL); } int BLF_height_max(int fontid) @@ -894,24 +897,27 @@ void blf_draw_buffer__end(void) { } -void BLF_draw_buffer_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) +void BLF_draw_buffer_ex(int fontid, + const char *str, + const size_t str_len, + struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); if (font && (font->buf_info.fbuf || font->buf_info.cbuf)) { blf_draw_buffer__start(font); if (font->flags & BLF_WORD_WRAP) { - blf_font_draw_buffer__wrap(font, str, len, r_info); + blf_font_draw_buffer__wrap(font, str, str_len, r_info); } else { - blf_font_draw_buffer(font, str, len, r_info); + blf_font_draw_buffer(font, str, str_len, r_info); } blf_draw_buffer__end(); } } -void BLF_draw_buffer(int fontid, const char *str, size_t len) +void BLF_draw_buffer(int fontid, const char *str, const size_t str_len) { - BLF_draw_buffer_ex(fontid, str, len, NULL); + BLF_draw_buffer_ex(fontid, str, str_len, NULL); } char *BLF_display_name_from_file(const char *filename) diff --git a/source/blender/blenfont/intern/blf_default.c b/source/blender/blenfont/intern/blf_default.c index 7bbc865128d..1b458e8aaef 100644 --- a/source/blender/blenfont/intern/blf_default.c +++ b/source/blender/blenfont/intern/blf_default.c @@ -68,23 +68,23 @@ int BLF_set_default(void) return global_font_default; } -void BLF_draw_default(float x, float y, float z, const char *str, size_t len) +void BLF_draw_default(float x, float y, float z, const char *str, const size_t str_len) { ASSERT_DEFAULT_SET; const uiStyle *style = UI_style_get(); BLF_size(global_font_default, style->widgetlabel.points, global_font_dpi); BLF_position(global_font_default, x, y, z); - BLF_draw(global_font_default, str, len); + BLF_draw(global_font_default, str, str_len); } /* same as above but call 'BLF_draw_ascii' */ -void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t len) +void BLF_draw_default_ascii(float x, float y, float z, const char *str, const size_t str_len) { ASSERT_DEFAULT_SET; const uiStyle *style = UI_style_get(); BLF_size(global_font_default, style->widgetlabel.points, global_font_dpi); BLF_position(global_font_default, x, y, z); - BLF_draw_ascii(global_font_default, str, len); /* XXX, use real length */ + BLF_draw_ascii(global_font_default, str, str_len); /* XXX, use real length */ } diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 75a2e893119..426008c9395 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -298,7 +298,7 @@ static void blf_batch_draw_end(void) */ BLI_INLINE GlyphBLF *blf_utf8_next_fast( - FontBLF *font, GlyphCacheBLF *gc, const char *str, size_t *i_p, uint *r_c) + FontBLF *font, GlyphCacheBLF *gc, const char *str, size_t str_len, size_t *i_p, uint *r_c) { GlyphBLF *g; if ((*r_c = str[*i_p]) < GLYPH_ASCII_TABLE_SIZE) { @@ -309,15 +309,13 @@ BLI_INLINE GlyphBLF *blf_utf8_next_fast( } (*i_p)++; } - else if ((*r_c = BLI_str_utf8_as_unicode_step(str, i_p)) != BLI_UTF8_ERR) { + else { + *r_c = BLI_str_utf8_as_unicode_step(str, str_len, i_p); g = blf_glyph_search(gc, *r_c); if (UNLIKELY(g == NULL)) { g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, *r_c), *r_c); } } - else { - g = NULL; - } return g; } @@ -365,7 +363,7 @@ BLI_INLINE void blf_kerning_step_fast(FontBLF *font, static void blf_font_draw_ex(FontBLF *font, GlyphCacheBLF *gc, const char *str, - size_t len, + const size_t str_len, struct ResultBLF *r_info, int pen_y) { @@ -374,15 +372,15 @@ static void blf_font_draw_ex(FontBLF *font, int pen_x = 0; size_t i = 0; - if (len == 0) { + if (str_len == 0) { /* early output, don't do any IMM OpenGL. */ return; } blf_batch_draw_begin(font); - while ((i < len) && str[i]) { - g = blf_utf8_next_fast(font, gc, str, &i, &c); + while ((i < str_len) && str[i]) { + g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -407,16 +405,16 @@ static void blf_font_draw_ex(FontBLF *font, r_info->width = pen_x; } } -void blf_font_draw(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +void blf_font_draw(FontBLF *font, const char *str, const size_t str_len, struct ResultBLF *r_info) { GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - blf_font_draw_ex(font, gc, str, len, r_info, 0); + blf_font_draw_ex(font, gc, str, str_len, r_info, 0); blf_glyph_cache_release(font); } /* faster version of blf_font_draw, ascii only for view dimensions */ static void blf_font_draw_ascii_ex( - FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, int pen_y) + FontBLF *font, const char *str, size_t str_len, struct ResultBLF *r_info, int pen_y) { unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev = NULL; @@ -426,7 +424,7 @@ static void blf_font_draw_ascii_ex( blf_batch_draw_begin(font); - while ((c = *(str++)) && len--) { + while ((c = *(str++)) && str_len--) { BLI_assert(c < GLYPH_ASCII_TABLE_SIZE); g = gc->glyph_ascii_table[c]; if (UNLIKELY(g == NULL)) { @@ -456,13 +454,16 @@ static void blf_font_draw_ascii_ex( blf_glyph_cache_release(font); } -void blf_font_draw_ascii(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +void blf_font_draw_ascii(FontBLF *font, + const char *str, + const size_t str_len, + struct ResultBLF *r_info) { - blf_font_draw_ascii_ex(font, str, len, r_info, 0); + blf_font_draw_ascii_ex(font, str, str_len, r_info, 0); } /* use fixed column width, but an utf8 character may occupy multiple columns */ -int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth) +int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int cwidth) { unsigned int c; GlyphBLF *g; @@ -474,8 +475,8 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth) blf_batch_draw_begin(font); - while ((i < len) && str[i]) { - g = blf_utf8_next_fast(font, gc, str, &i, &c); + while ((i < str_len) && str[i]) { + g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -505,14 +506,14 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Text Drawgin: Buffer +/** \name Text Drawing: Buffer * \{ */ /* Sanity checks are done by BLF_draw_buffer() */ static void blf_font_draw_buffer_ex(FontBLF *font, GlyphCacheBLF *gc, const char *str, - size_t len, + const size_t str_len, struct ResultBLF *r_info, int pen_y) { @@ -531,8 +532,8 @@ static void blf_font_draw_buffer_ex(FontBLF *font, /* another buffer specific call for color conversion */ - while ((i < len) && str[i]) { - g = blf_utf8_next_fast(font, gc, str, &i, &c); + while ((i < str_len) && str[i]) { + g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -646,10 +647,13 @@ static void blf_font_draw_buffer_ex(FontBLF *font, } } -void blf_font_draw_buffer(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +void blf_font_draw_buffer(FontBLF *font, + const char *str, + const size_t str_len, + struct ResultBLF *r_info) { GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - blf_font_draw_buffer_ex(font, gc, str, len, r_info, 0); + blf_font_draw_buffer_ex(font, gc, str, str_len, r_info, 0); blf_glyph_cache_release(font); } @@ -685,7 +689,7 @@ static bool blf_font_width_to_strlen_glyph_process(FontBLF *font, } size_t blf_font_width_to_strlen( - FontBLF *font, const char *str, size_t len, float width, float *r_width) + FontBLF *font, const char *str, const size_t str_len, float width, float *r_width) { unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev; @@ -695,9 +699,9 @@ size_t blf_font_width_to_strlen( GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); const int width_i = (int)width; - for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL, c_prev = 0; (i < len) && str[i]; + for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL, c_prev = 0; (i < str_len) && str[i]; i_prev = i, width_new = pen_x, c_prev = c, g_prev = g) { - g = blf_utf8_next_fast(font, gc, str, &i, &c); + g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); if (blf_font_width_to_strlen_glyph_process(font, c_prev, c, g_prev, g, &pen_x, width_i)) { break; @@ -713,7 +717,7 @@ size_t blf_font_width_to_strlen( } size_t blf_font_width_to_rstrlen( - FontBLF *font, const char *str, size_t len, float width, float *r_width) + FontBLF *font, const char *str, const size_t str_len, float width, float *r_width) { unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev; @@ -724,14 +728,14 @@ size_t blf_font_width_to_rstrlen( GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); const int width_i = (int)width; - i = BLI_strnlen(str, len); + i = BLI_strnlen(str, str_len); s = BLI_str_find_prev_char_utf8(str, &str[i]); i = (size_t)((s != NULL) ? s - str : 0); s_prev = BLI_str_find_prev_char_utf8(str, s); i_prev = (size_t)((s_prev != NULL) ? s_prev - str : 0); i_tmp = i; - g = blf_utf8_next_fast(font, gc, str, &i_tmp, &c); + g = blf_utf8_next_fast(font, gc, str, str_len, &i_tmp, &c); for (width_new = pen_x = 0; (s != NULL); i = i_prev, s = s_prev, c = c_prev, g = g_prev, g_prev = NULL, width_new = pen_x) { s_prev = BLI_str_find_prev_char_utf8(str, s); @@ -739,7 +743,7 @@ size_t blf_font_width_to_rstrlen( if (s_prev != NULL) { i_tmp = i_prev; - g_prev = blf_utf8_next_fast(font, gc, str, &i_tmp, &c_prev); + g_prev = blf_utf8_next_fast(font, gc, str, str_len, &i_tmp, &c_prev); BLI_assert(i_tmp == i); } @@ -765,7 +769,7 @@ size_t blf_font_width_to_rstrlen( static void blf_font_boundbox_ex(FontBLF *font, GlyphCacheBLF *gc, const char *str, - size_t len, + const size_t str_len, rctf *box, struct ResultBLF *r_info, int pen_y) @@ -781,8 +785,8 @@ static void blf_font_boundbox_ex(FontBLF *font, box->ymin = 32000.0f; box->ymax = -32000.0f; - while ((i < len) && str[i]) { - g = blf_utf8_next_fast(font, gc, str, &i, &c); + while ((i < str_len) && str[i]) { + g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -829,16 +833,16 @@ static void blf_font_boundbox_ex(FontBLF *font, } } void blf_font_boundbox( - FontBLF *font, const char *str, size_t len, rctf *r_box, struct ResultBLF *r_info) + FontBLF *font, const char *str, const size_t str_len, rctf *r_box, struct ResultBLF *r_info) { GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - blf_font_boundbox_ex(font, gc, str, len, r_box, r_info, 0); + blf_font_boundbox_ex(font, gc, str, str_len, r_box, r_info, 0); blf_glyph_cache_release(font); } void blf_font_width_and_height(FontBLF *font, const char *str, - size_t len, + const size_t str_len, float *r_width, float *r_height, struct ResultBLF *r_info) @@ -856,16 +860,19 @@ void blf_font_width_and_height(FontBLF *font, } if (font->flags & BLF_WORD_WRAP) { - blf_font_boundbox__wrap(font, str, len, &box, r_info); + blf_font_boundbox__wrap(font, str, str_len, &box, r_info); } else { - blf_font_boundbox(font, str, len, &box, r_info); + blf_font_boundbox(font, str, str_len, &box, r_info); } *r_width = (BLI_rctf_size_x(&box) * xa); *r_height = (BLI_rctf_size_y(&box) * ya); } -float blf_font_width(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +float blf_font_width(FontBLF *font, + const char *str, + const size_t str_len, + struct ResultBLF *r_info) { float xa; rctf box; @@ -878,15 +885,18 @@ float blf_font_width(FontBLF *font, const char *str, size_t len, struct ResultBL } if (font->flags & BLF_WORD_WRAP) { - blf_font_boundbox__wrap(font, str, len, &box, r_info); + blf_font_boundbox__wrap(font, str, str_len, &box, r_info); } else { - blf_font_boundbox(font, str, len, &box, r_info); + blf_font_boundbox(font, str, str_len, &box, r_info); } return BLI_rctf_size_x(&box) * xa; } -float blf_font_height(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +float blf_font_height(FontBLF *font, + const char *str, + const size_t str_len, + struct ResultBLF *r_info) { float ya; rctf box; @@ -899,10 +909,10 @@ float blf_font_height(FontBLF *font, const char *str, size_t len, struct ResultB } if (font->flags & BLF_WORD_WRAP) { - blf_font_boundbox__wrap(font, str, len, &box, r_info); + blf_font_boundbox__wrap(font, str, str_len, &box, r_info); } else { - blf_font_boundbox(font, str, len, &box, r_info); + blf_font_boundbox(font, str, str_len, &box, r_info); } return BLI_rctf_size_y(&box) * ya; } @@ -930,7 +940,7 @@ float blf_font_fixed_width(FontBLF *font) static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, GlyphCacheBLF *gc, const char *str, - size_t len, + const size_t str_len, BLF_GlyphBoundsFn user_fn, void *user_data, struct ResultBLF *r_info, @@ -942,14 +952,14 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, size_t i = 0, i_curr; rcti gbox; - if (len == 0) { + if (str_len == 0) { /* early output. */ return; } - while ((i < len) && str[i]) { + while ((i < str_len) && str[i]) { i_curr = i; - g = blf_utf8_next_fast(font, gc, str, &i, &c); + g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -981,13 +991,13 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, } void blf_font_boundbox_foreach_glyph(FontBLF *font, const char *str, - size_t len, + const size_t str_len, BLF_GlyphBoundsFn user_fn, void *user_data, struct ResultBLF *r_info) { GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - blf_font_boundbox_foreach_glyph_ex(font, gc, str, len, user_fn, user_data, r_info, 0); + blf_font_boundbox_foreach_glyph_ex(font, gc, str, str_len, user_fn, user_data, r_info, 0); blf_glyph_cache_release(font); } @@ -1008,12 +1018,12 @@ void blf_font_boundbox_foreach_glyph(FontBLF *font, */ static void blf_font_wrap_apply(FontBLF *font, const char *str, - size_t len, + const size_t str_len, struct ResultBLF *r_info, void (*callback)(FontBLF *font, GlyphCacheBLF *gc, const char *str, - size_t len, + const size_t str_len, int pen_y, void *userdata), void *userdata) @@ -1032,14 +1042,14 @@ static void blf_font_wrap_apply(FontBLF *font, size_t start, last[2]; } wrap = {font->wrap_width != -1 ? font->wrap_width : INT_MAX, 0, {0, 0}}; - // printf("%s wrapping (%d, %d) `%s`:\n", __func__, len, strlen(str), str); - while ((i < len) && str[i]) { + // printf("%s wrapping (%d, %d) `%s`:\n", __func__, str_len, strlen(str), str); + while ((i < str_len) && str[i]) { /* wrap vars */ size_t i_curr = i; bool do_draw = false; - g = blf_utf8_next_fast(font, gc, str, &i, &c); + g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -1061,7 +1071,7 @@ static void blf_font_wrap_apply(FontBLF *font, if (UNLIKELY((pen_x_next >= wrap.wrap_width) && (wrap.start != wrap.last[0]))) { do_draw = true; } - else if (UNLIKELY(((i < len) && str[i]) == 0)) { + else if (UNLIKELY(((i < str_len) && str[i]) == 0)) { /* need check here for trailing newline, else we draw it */ wrap.last[0] = i + ((g->c != '\n') ? 1 : 0); wrap.last[1] = i; @@ -1112,54 +1122,61 @@ static void blf_font_wrap_apply(FontBLF *font, static void blf_font_draw__wrap_cb(FontBLF *font, GlyphCacheBLF *gc, const char *str, - size_t len, + const size_t str_len, int pen_y, void *UNUSED(userdata)) { - blf_font_draw_ex(font, gc, str, len, NULL, pen_y); + blf_font_draw_ex(font, gc, str, str_len, NULL, pen_y); } -void blf_font_draw__wrap(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +void blf_font_draw__wrap(FontBLF *font, + const char *str, + const size_t str_len, + struct ResultBLF *r_info) { - blf_font_wrap_apply(font, str, len, r_info, blf_font_draw__wrap_cb, NULL); + blf_font_wrap_apply(font, str, str_len, r_info, blf_font_draw__wrap_cb, NULL); } /* blf_font_boundbox__wrap */ -static void blf_font_boundbox_wrap_cb( - FontBLF *font, GlyphCacheBLF *gc, const char *str, size_t len, int pen_y, void *userdata) +static void blf_font_boundbox_wrap_cb(FontBLF *font, + GlyphCacheBLF *gc, + const char *str, + const size_t str_len, + int pen_y, + void *userdata) { rctf *box = userdata; rctf box_single; - blf_font_boundbox_ex(font, gc, str, len, &box_single, NULL, pen_y); + blf_font_boundbox_ex(font, gc, str, str_len, &box_single, NULL, pen_y); BLI_rctf_union(box, &box_single); } void blf_font_boundbox__wrap( - FontBLF *font, const char *str, size_t len, rctf *box, struct ResultBLF *r_info) + FontBLF *font, const char *str, const size_t str_len, rctf *box, struct ResultBLF *r_info) { box->xmin = 32000.0f; box->xmax = -32000.0f; box->ymin = 32000.0f; box->ymax = -32000.0f; - blf_font_wrap_apply(font, str, len, r_info, blf_font_boundbox_wrap_cb, box); + blf_font_wrap_apply(font, str, str_len, r_info, blf_font_boundbox_wrap_cb, box); } /* blf_font_draw_buffer__wrap */ static void blf_font_draw_buffer__wrap_cb(FontBLF *font, GlyphCacheBLF *gc, const char *str, - size_t len, + const size_t str_len, int pen_y, void *UNUSED(userdata)) { - blf_font_draw_buffer_ex(font, gc, str, len, NULL, pen_y); + blf_font_draw_buffer_ex(font, gc, str, str_len, NULL, pen_y); } void blf_font_draw_buffer__wrap(FontBLF *font, const char *str, - size_t len, + const size_t str_len, struct ResultBLF *r_info) { - blf_font_wrap_apply(font, str, len, r_info, blf_font_draw_buffer__wrap_cb, NULL); + blf_font_wrap_apply(font, str, str_len, r_info, blf_font_draw_buffer__wrap_cb, NULL); } /** \} */ @@ -1170,20 +1187,21 @@ void blf_font_draw_buffer__wrap(FontBLF *font, int blf_font_count_missing_chars(FontBLF *font, const char *str, - const size_t len, + const size_t str_len, int *r_tot_chars) { int missing = 0; size_t i = 0; *r_tot_chars = 0; - while (i < len) { + while (i < str_len) { unsigned int c; if ((c = str[i]) < GLYPH_ASCII_TABLE_SIZE) { i++; } - else if ((c = BLI_str_utf8_as_unicode_step(str, &i)) != BLI_UTF8_ERR) { + else { + c = BLI_str_utf8_as_unicode_step(str, str_len, &i); if (FT_Get_Char_Index((font)->face, c) == 0) { missing++; } diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index ab2a26b1e06..6fd5e8b7503 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -53,46 +53,55 @@ struct FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, int mem_size); void blf_font_size(struct FontBLF *font, unsigned int size, unsigned int dpi); -void blf_font_draw(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info); +void blf_font_draw(struct FontBLF *font, + const char *str, + size_t str_len, + struct ResultBLF *r_info); void blf_font_draw__wrap(struct FontBLF *font, const char *str, - size_t len, + size_t str_len, struct ResultBLF *r_info); void blf_font_draw_ascii(struct FontBLF *font, const char *str, - size_t len, + size_t str_len, struct ResultBLF *r_info); -int blf_font_draw_mono(struct FontBLF *font, const char *str, size_t len, int cwidth); +int blf_font_draw_mono(struct FontBLF *font, const char *str, size_t str_len, int cwidth); void blf_font_draw_buffer(struct FontBLF *font, const char *str, - size_t len, + size_t str_len, struct ResultBLF *r_info); void blf_font_draw_buffer__wrap(struct FontBLF *font, const char *str, - size_t len, + size_t str_len, struct ResultBLF *r_info); size_t blf_font_width_to_strlen( - struct FontBLF *font, const char *str, size_t len, float width, float *r_width); + struct FontBLF *font, const char *str, size_t str_len, float width, float *r_width); size_t blf_font_width_to_rstrlen( - struct FontBLF *font, const char *str, size_t len, float width, float *r_width); + struct FontBLF *font, const char *str, size_t str_len, float width, float *r_width); void blf_font_boundbox(struct FontBLF *font, const char *str, - size_t len, + size_t str_len, struct rctf *r_box, struct ResultBLF *r_info); void blf_font_boundbox__wrap(struct FontBLF *font, const char *str, - size_t len, + size_t str_len, struct rctf *r_box, struct ResultBLF *r_info); void blf_font_width_and_height(struct FontBLF *font, const char *str, - size_t len, + size_t str_len, float *r_width, float *r_height, struct ResultBLF *r_info); -float blf_font_width(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info); -float blf_font_height(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info); +float blf_font_width(struct FontBLF *font, + const char *str, + size_t str_len, + struct ResultBLF *r_info); +float blf_font_height(struct FontBLF *font, + const char *str, + size_t str_len, + struct ResultBLF *r_info); float blf_font_fixed_width(struct FontBLF *font); int blf_font_height_max(struct FontBLF *font); int blf_font_width_max(struct FontBLF *font); @@ -103,7 +112,7 @@ char *blf_display_name(struct FontBLF *font); void blf_font_boundbox_foreach_glyph(struct FontBLF *font, const char *str, - size_t len, + size_t str_len, bool (*user_fn)(const char *str, const size_t str_step_ofs, const struct rcti *glyph_step_bounds, @@ -116,7 +125,7 @@ void blf_font_boundbox_foreach_glyph(struct FontBLF *font, int blf_font_count_missing_chars(struct FontBLF *font, const char *str, - const size_t len, + const size_t str_len, int *r_tot_chars); void blf_font_free(struct FontBLF *font); diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index bb875f8d1c9..a50faedcc3c 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -166,8 +166,14 @@ struct ID *BKE_libblock_find_name(struct Main *bmain, */ typedef enum eLibIDDuplicateFlags { /** This call to a duplicate function is part of another call for some parent ID. - * Therefore, this sub-process should not clear `newid` pointers, nor handle remapping itself. */ + * Therefore, this sub-process should not clear `newid` pointers, nor handle remapping itself. + * NOTE: In some cases (like Object one), the duplicate function may be called on the root ID + * with this flag set, as remapping and/or other similar tasks need to be handled by the caller. + */ LIB_ID_DUPLICATE_IS_SUBPROCESS = 1 << 0, + /** This call is performed on a 'root' ID, and should therefore perform some decisions regarding + * sub-IDs (dependencies), check for linked vs. locale data, etc. */ + LIB_ID_DUPLICATE_IS_ROOT_ID = 1 << 1, } eLibIDDuplicateFlags; /* lib_remap.c (keep here since they're general functions) */ diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index ae464a48e9e..dbcefb8b6d5 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -143,11 +143,6 @@ int BKE_mesh_mface_index_validate(struct MFace *mface, struct Mesh *BKE_mesh_from_object(struct Object *ob); void BKE_mesh_assign_object(struct Main *bmain, struct Object *ob, struct Mesh *me); void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me); -void BKE_mesh_from_nurbs_displist(struct Main *bmain, - struct Object *ob, - struct ListBase *dispbase, - const char *obdata_name, - bool temporary); void BKE_mesh_to_curve_nurblist(const struct Mesh *me, struct ListBase *nurblist, const int edge_users_test); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index c4393246926..06528cd213c 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -346,7 +346,7 @@ typedef struct bNodeType { #define NODE_CLASS_OP_FILTER 5 #define NODE_CLASS_GROUP 6 // #define NODE_CLASS_FILE 7 -#define NODE_CLASS_CONVERTOR 8 +#define NODE_CLASS_CONVERTER 8 #define NODE_CLASS_MATTE 9 #define NODE_CLASS_DISTORT 10 // #define NODE_CLASS_OP_DYNAMIC 11 /* deprecated */ diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index e5b547d2557..78a6e47ec48 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -368,7 +368,10 @@ struct ModifierData *object_copy_particle_system(struct Main *bmain, struct Scene *scene, struct Object *ob, const struct ParticleSystem *psys_orig); -void object_remove_particle_system(struct Main *bmain, struct Scene *scene, struct Object *ob); +void object_remove_particle_system(struct Main *bmain, + struct Scene *scene, + struct Object *ob, + struct ParticleSystem *psys); struct ParticleSettings *BKE_particlesettings_add(struct Main *bmain, const char *name); void psys_reset(struct ParticleSystem *psys, int mode); diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc index 164f921c7ac..707201207d9 100644 --- a/source/blender/blenkernel/intern/bvhutils.cc +++ b/source/blender/blenkernel/intern/bvhutils.cc @@ -1254,11 +1254,10 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data, bool in_cache = bvhcache_find( bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex); BVHCache *bvh_cache = *bvh_cache_p; - bvhtree_balance(tree, true); - if (in_cache == false) { tree = bvhtree_from_editmesh_looptri_create_tree( epsilon, tree_type, axis, em, looptri_mask, looptri_num_active); + bvhtree_balance(tree, true); /* Save on cache for later use */ // printf("BVHTree built and saved on cache\n"); diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 46b079fb42e..b77855f8f95 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -92,11 +92,6 @@ static void camera_copy_data(Main *UNUSED(bmain), BLI_duplicatelist(&cam_dst->bg_images, &cam_src->bg_images); } -static void camera_make_local(Main *bmain, ID *id, const int flags) -{ - BKE_lib_id_make_local_generic(bmain, id, flags); -} - /** Free (or release) any data used by this camera (does not free the camera itself). */ static void camera_free_data(ID *id) { @@ -192,7 +187,7 @@ IDTypeInfo IDType_ID_CA = { .init_data = camera_init_data, .copy_data = camera_copy_data, .free_data = camera_free_data, - .make_local = camera_make_local, + .make_local = NULL, .foreach_id = camera_foreach_id, .foreach_cache = NULL, .owner_get = NULL, diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index d36e9b67d00..2d172f23428 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -692,14 +692,18 @@ Collection *BKE_collection_duplicate(Main *bmain, eLibIDDuplicateFlags duplicate_options) { const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0; + const bool is_root_id = (duplicate_options & LIB_ID_DUPLICATE_IS_ROOT_ID) != 0; if (!is_subprocess) { BKE_main_id_newptr_and_tag_clear(bmain); + } + if (is_root_id) { /* In case root duplicated ID is linked, assume we want to get a local copy of it and duplicate * all expected linked data. */ if (ID_IS_LINKED(collection)) { duplicate_flags |= USER_DUP_LINKED_ID; } + duplicate_options &= ~LIB_ID_DUPLICATE_IS_ROOT_ID; } Collection *collection_new = collection_duplicate_recursive( diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc index 0f218d6166c..5bca20ecd44 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.cc +++ b/source/blender/blenkernel/intern/gpencil_geom.cc @@ -620,7 +620,10 @@ bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const } if (new_count == 1) { - BKE_gpencil_free_stroke_weights(gps); + if (gps->dvert) { + BKE_gpencil_free_stroke_weights(gps); + MEM_freeN(gps->dvert); + } MEM_freeN(gps->points); gps->points = nullptr; gps->dvert = nullptr; @@ -628,27 +631,24 @@ bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const return false; } - new_pt = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * new_count, "gp_stroke_points_trimmed"); - - for (int i = 0; i < new_count; i++) { - memcpy(&new_pt[i], &pt[i + index_from], sizeof(bGPDspoint)); - } + new_pt = (bGPDspoint *)MEM_mallocN(sizeof(bGPDspoint) * new_count, "gp_stroke_points_trimmed"); + memcpy(new_pt, &pt[index_from], sizeof(bGPDspoint) * new_count); if (gps->dvert) { - new_dv = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * new_count, + new_dv = (MDeformVert *)MEM_mallocN(sizeof(MDeformVert) * new_count, "gp_stroke_dverts_trimmed"); for (int i = 0; i < new_count; i++) { dv = &gps->dvert[i + index_from]; new_dv[i].flag = dv->flag; new_dv[i].totweight = dv->totweight; - new_dv[i].dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * dv->totweight, + new_dv[i].dw = (MDeformWeight *)MEM_mallocN(sizeof(MDeformWeight) * dv->totweight, "gp_stroke_dverts_dw_trimmed"); for (int j = 0; j < dv->totweight; j++) { new_dv[i].dw[j].weight = dv->dw[j].weight; new_dv[i].dw[j].def_nr = dv->dw[j].def_nr; } - BKE_defvert_clear(dv); } + BKE_gpencil_free_stroke_weights(gps); MEM_freeN(gps->dvert); gps->dvert = new_dv; } @@ -692,25 +692,21 @@ bool BKE_gpencil_stroke_split(bGPdata *gpd, gpf, gps, gps->mat_nr, new_count, gps->thickness); new_pt = new_gps->points; /* Allocated from above. */ - - for (int i = 0; i < new_count; i++) { - memcpy(&new_pt[i], &pt[i + before_index], sizeof(bGPDspoint)); - } + memcpy(new_pt, &pt[before_index], sizeof(bGPDspoint) * new_count); if (gps->dvert) { - new_dv = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * new_count, + new_dv = (MDeformVert *)MEM_mallocN(sizeof(MDeformVert) * new_count, "gp_stroke_dverts_remaining(MDeformVert)"); for (int i = 0; i < new_count; i++) { dv = &gps->dvert[i + before_index]; new_dv[i].flag = dv->flag; new_dv[i].totweight = dv->totweight; - new_dv[i].dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * dv->totweight, + new_dv[i].dw = (MDeformWeight *)MEM_mallocN(sizeof(MDeformWeight) * dv->totweight, "gp_stroke_dverts_dw_remaining(MDeformWeight)"); for (int j = 0; j < dv->totweight; j++) { new_dv[i].dw[j].weight = dv->dw[j].weight; new_dv[i].dw[j].def_nr = dv->dw[j].def_nr; } - BKE_defvert_clear(dv); } new_gps->dvert = new_dv; } diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 0f880d16358..aa458bc1b27 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -153,7 +153,7 @@ static int lib_id_clear_library_data_users_update_cb(LibraryIDLinkCallbackData * * Pull an ID out of a library (make it local). Only call this for IDs that * don't have other library users. */ -static void lib_id_clear_library_data_ex(Main *bmain, ID *id) +void BKE_lib_id_clear_library_data(Main *bmain, ID *id) { const bool id_in_mainlist = (id->tag & LIB_TAG_NO_MAIN) == 0 && (id->flag & LIB_EMBEDDED_DATA) == 0; @@ -193,17 +193,12 @@ static void lib_id_clear_library_data_ex(Main *bmain, ID *id) * IDs here, this is down automatically in `lib_id_expand_local_cb()`. */ Key *key = BKE_key_from_id(id); if (key != NULL) { - lib_id_clear_library_data_ex(bmain, &key->id); + BKE_lib_id_clear_library_data(bmain, &key->id); } DEG_relations_tag_update(bmain); } -void BKE_lib_id_clear_library_data(Main *bmain, ID *id) -{ - lib_id_clear_library_data_ex(bmain, id); -} - void id_lib_extern(ID *id) { if (id && ID_IS_LINKED(id)) { @@ -369,7 +364,7 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data) if (*id_pointer != NULL && ID_IS_LINKED(*id_pointer)) { BLI_assert(*id_pointer != id_self); - lib_id_clear_library_data_ex(bmain, *id_pointer); + BKE_lib_id_clear_library_data(bmain, *id_pointer); } return IDWALK_RET_NOP; } @@ -429,7 +424,7 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags) if (lib_local || is_local) { if (!is_lib) { - lib_id_clear_library_data_ex(bmain, id); + BKE_lib_id_clear_library_data(bmain, id); BKE_lib_id_expand_local(bmain, id); } else { @@ -1481,7 +1476,7 @@ static bool id_name_final_build(char *name, char *base_name, size_t base_name_le /* Code above may have generated invalid utf-8 string, due to raw truncation. * Ensure we get a valid one now. */ - base_name_len -= (size_t)BLI_utf8_invalid_strip(base_name, base_name_len); + base_name_len -= (size_t)BLI_str_utf8_invalid_strip(base_name, base_name_len); /* Also truncate orig name, and start the whole check again. */ name[base_name_len] = '\0'; @@ -1731,7 +1726,7 @@ bool BKE_id_new_name_validate(ListBase *lb, ID *id, const char *tname, const boo else { /* disallow non utf8 chars, * the interface checks for this but new ID's based on file names don't */ - BLI_utf8_invalid_strip(name, strlen(name)); + BLI_str_utf8_invalid_strip(name, strlen(name)); } ID *id_sorting_hint = NULL; @@ -2014,7 +2009,7 @@ void BKE_library_make_local(Main *bmain, * currently there are some indirect usages. So instead of making a copy that we'll likely * get rid of later, directly make that data block local. * Saves a tremendous amount of time with complex scenes... */ - lib_id_clear_library_data_ex(bmain, id); + BKE_lib_id_clear_library_data(bmain, id); BKE_lib_id_expand_local(bmain, id); id->tag &= ~LIB_TAG_DOIT; diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index eb8e6aad736..e3650e03c8a 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -466,8 +466,10 @@ static int customdata_compare( int vtot = m1->totvert; for (j = 0; j < vtot; j++, v1++, v2++) { - if (len_squared_v3v3(v1->co, v2->co) > thresh_sq) { - return MESHCMP_VERTCOMISMATCH; + for (int k = 0; k < 3; k++) { + if (compare_threshold_relative(v1->co[k], v2->co[k], thresh)) { + return MESHCMP_VERTCOMISMATCH; + } } /* I don't care about normals, let's just do coordinates. */ } @@ -547,8 +549,7 @@ static int customdata_compare( int ltot = m1->totloop; for (j = 0; j < ltot; j++, lp1++, lp2++) { - if (abs(lp1->r - lp2->r) > thresh || abs(lp1->g - lp2->g) > thresh || - abs(lp1->b - lp2->b) > thresh || abs(lp1->a - lp2->a) > thresh) { + if (lp1->r != lp2->r || lp1->g != lp2->g || lp1->b != lp2->b || lp1->a != lp2->a) { return MESHCMP_LOOPCOLMISMATCH; } } @@ -583,7 +584,7 @@ static int customdata_compare( const float *l2_data = l2->data; for (int i = 0; i < total_length; i++) { - if (fabsf(l1_data[i] - l2_data[i]) > thresh) { + if (compare_threshold_relative(l1_data[i], l2_data[i], thresh)) { return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; } } @@ -594,7 +595,10 @@ static int customdata_compare( const float(*l2_data)[2] = l2->data; for (int i = 0; i < total_length; i++) { - if (len_squared_v2v2(l1_data[i], l2_data[i]) > thresh_sq) { + if (compare_threshold_relative(l1_data[i][0], l2_data[i][0], thresh)) { + return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; + } + if (compare_threshold_relative(l1_data[i][1], l2_data[i][1], thresh)) { return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; } } @@ -605,7 +609,13 @@ static int customdata_compare( const float(*l2_data)[3] = l2->data; for (int i = 0; i < total_length; i++) { - if (len_squared_v3v3(l1_data[i], l2_data[i]) > thresh_sq) { + if (compare_threshold_relative(l1_data[i][0], l2_data[i][0], thresh)) { + return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; + } + if (compare_threshold_relative(l1_data[i][1], l2_data[i][1], thresh)) { + return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; + } + if (compare_threshold_relative(l1_data[i][2], l2_data[i][2], thresh)) { return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; } } @@ -639,7 +649,7 @@ static int customdata_compare( for (int i = 0; i < total_length; i++) { for (j = 0; j < 4; j++) { - if (fabsf(l1_data[i].color[j] - l2_data[i].color[j]) > thresh) { + if (compare_threshold_relative(l1_data[i].color[j], l2_data[i].color[j], thresh)) { return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; } } diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index 4b1eb5b39ce..d5524312612 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -548,11 +548,12 @@ Mesh *BKE_mesh_new_nomain_from_curve(const Object *ob) return BKE_mesh_new_nomain_from_curve_displist(ob, &disp); } -/* this may fail replacing ob->data, be sure to check ob->type */ -void BKE_mesh_from_nurbs_displist( - Main *bmain, Object *ob, ListBase *dispbase, const char *obdata_name, bool temporary) +static void mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const char *obdata_name) { - Object *ob1; + if (ob->runtime.data_eval && GS(((ID *)ob->runtime.data_eval)->name) != ID_ME) { + return; + } + Mesh *me_eval = (Mesh *)ob->runtime.data_eval; Mesh *me; MVert *allvert = NULL; @@ -581,12 +582,7 @@ void BKE_mesh_from_nurbs_displist( } /* make mesh */ - if (bmain != NULL) { - me = BKE_mesh_add(bmain, obdata_name); - } - else { - me = BKE_id_new_nomain(ID_ME, obdata_name); - } + me = BKE_id_new_nomain(ID_ME, obdata_name); me->totvert = totvert; me->totedge = totedge; @@ -607,12 +603,7 @@ void BKE_mesh_from_nurbs_displist( BKE_mesh_calc_normals(me); } else { - if (bmain != NULL) { - me = BKE_mesh_add(bmain, obdata_name); - } - else { - me = BKE_id_new_nomain(ID_ME, obdata_name); - } + me = BKE_id_new_nomain(ID_ME, obdata_name); ob->runtime.data_eval = NULL; BKE_mesh_nomain_to_mesh(me_eval, me, ob, &CD_MASK_MESH, true); @@ -641,30 +632,10 @@ void BKE_mesh_from_nurbs_displist( ob->data = me; ob->type = OB_MESH; - /* other users */ - if (bmain != NULL) { - ob1 = bmain->objects.first; - while (ob1) { - if (ob1->data == cu) { - ob1->type = OB_MESH; - - id_us_min((ID *)ob1->data); - ob1->data = ob->data; - id_us_plus((ID *)ob1->data); - } - ob1 = ob1->id.next; - } - } - - if (temporary) { - /* For temporary objects in BKE_mesh_new_from_object don't remap - * the entire scene with associated depsgraph updates, which are - * problematic for renderers exporting data. */ - BKE_id_free(NULL, cu); - } - else { - BKE_id_free_us(bmain, cu); - } + /* For temporary objects in BKE_mesh_new_from_object don't remap + * the entire scene with associated depsgraph updates, which are + * problematic for renderers exporting data. */ + BKE_id_free(NULL, cu); } typedef struct EdgeLink { @@ -965,7 +936,7 @@ void BKE_pointcloud_to_mesh(Main *bmain, Depsgraph *depsgraph, Scene *UNUSED(sce /* Create a temporary object to be used for nurbs-to-mesh conversion. * - * This is more complex that it should be because BKE_mesh_from_nurbs_displist() will do more than + * This is more complex that it should be because #mesh_from_nurbs_displist will do more than * simply conversion and will attempt to take over ownership of evaluated result and will also * modify the input object. */ static Object *object_for_curve_to_mesh_create(Object *object) @@ -1063,7 +1034,7 @@ static void curve_to_mesh_eval_ensure(Object *object) * they are only used for modifier stack, which we have explicitly disabled for all objects. * * TODO(sergey): This is a very fragile logic, but proper solution requires re-writing quite a - * bit of internal functions (BKE_mesh_from_nurbs_displist, BKE_mesh_nomain_to_mesh) and also + * bit of internal functions (#mesh_from_nurbs_displist, BKE_mesh_nomain_to_mesh) and also * Mesh From Curve operator. * Brecht says hold off with that. */ Mesh *mesh_eval = NULL; @@ -1102,10 +1073,10 @@ static Mesh *mesh_new_from_curve_type_object(Object *object) temp_curve->editnurb = NULL; /* Convert to mesh. */ - BKE_mesh_from_nurbs_displist( - NULL, temp_object, &temp_object->runtime.curve_cache->disp, curve->id.name + 2, true); + mesh_from_nurbs_displist( + temp_object, &temp_object->runtime.curve_cache->disp, curve->id.name + 2); - /* BKE_mesh_from_nurbs_displist changes the type to a mesh, check it worked. If it didn't + /* #mesh_from_nurbs_displist changes the type to a mesh, check it worked. If it didn't * the curve did not have any segments or otherwise would have generated an empty mesh. */ if (temp_object->type != OB_MESH) { BKE_id_free(NULL, temp_object->data); @@ -1117,7 +1088,7 @@ static Mesh *mesh_new_from_curve_type_object(Object *object) BKE_id_free(NULL, temp_object); - /* NOTE: Materials are copied in BKE_mesh_from_nurbs_displist(). */ + /* NOTE: Materials are copied in #mesh_from_nurbs_displist(). */ return mesh_result; } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 1c08a46adc3..6e26ed4925d 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -2614,17 +2614,21 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src) Object *BKE_object_duplicate(Main *bmain, Object *ob, eDupli_ID_Flags dupflag, - const eLibIDDuplicateFlags duplicate_options) + eLibIDDuplicateFlags duplicate_options) { const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0; + const bool is_root_id = (duplicate_options & LIB_ID_DUPLICATE_IS_ROOT_ID) != 0; if (!is_subprocess) { BKE_main_id_newptr_and_tag_clear(bmain); + } + if (is_root_id) { /* In case root duplicated ID is linked, assume we want to get a local copy of it and duplicate * all expected linked data. */ if (ID_IS_LINKED(ob)) { dupflag |= USER_DUP_LINKED_ID; } + duplicate_options &= ~LIB_ID_DUPLICATE_IS_ROOT_ID; } Material ***matarar; diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 29849c69b6f..50b0fb1c9f5 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -3967,16 +3967,18 @@ ModifierData *object_copy_particle_system(Main *bmain, return object_add_or_copy_particle_system(bmain, scene, ob, NULL, psys_orig); } -void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob) +void object_remove_particle_system(Main *bmain, + Scene *UNUSED(scene), + Object *ob, + ParticleSystem *psys) { - ParticleSystem *psys = psys_get_current(ob); - ParticleSystemModifierData *psmd; - ModifierData *md; - - if (!psys) { + if (!ob || !psys) { return; } + ParticleSystemModifierData *psmd; + ModifierData *md; + /* Clear particle system in fluid modifier. */ if ((md = BKE_modifiers_findby_type(ob, eModifierType_Fluid))) { FluidModifierData *fmd = (FluidModifierData *)md; diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 3fe00adc4d5..5a668746956 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -1176,11 +1176,6 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id) seq->flag |= SEQ_EFFECT_NOT_LOADED; } - if (seq->type == SEQ_TYPE_SPEED) { - SpeedControlVars *s = seq->effectdata; - s->frameMap = NULL; - } - if (seq->type == SEQ_TYPE_TEXT) { TextVars *t = seq->effectdata; t->text_blf_id = SEQ_FONT_NOT_LOADED; @@ -1989,9 +1984,12 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type) if (type == SCE_COPY_FULL) { /* Scene duplication is always root of duplication currently. */ const bool is_subprocess = false; + const bool is_root_id = true; if (!is_subprocess) { BKE_main_id_newptr_and_tag_clear(bmain); + } + if (is_root_id) { /* In case root duplicated ID is linked, assume we want to get a local copy of it and * duplicate all expected linked data. */ if (ID_IS_LINKED(sce)) { diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc index dda7abea0fc..732fabc6582 100644 --- a/source/blender/blenkernel/intern/spline_base.cc +++ b/source/blender/blenkernel/intern/spline_base.cc @@ -123,7 +123,7 @@ int Spline::evaluated_edges_size() const float Spline::length() const { Span<float> lengths = this->evaluated_lengths(); - return (lengths.size() == 0) ? 0 : this->evaluated_lengths().last(); + return lengths.is_empty() ? 0.0f : this->evaluated_lengths().last(); } int Spline::segments_size() const diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 275cf0d4c38..7f1f6590e48 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -308,7 +308,7 @@ int txt_extended_ascii_as_utf8(char **str) int added = 0; while ((*str)[i]) { - if ((bad_char = BLI_utf8_invalid_byte(*str + i, length - i)) == -1) { + if ((bad_char = BLI_str_utf8_invalid_byte(*str + i, length - i)) == -1) { break; } @@ -322,7 +322,7 @@ int txt_extended_ascii_as_utf8(char **str) i = 0; while ((*str)[i]) { - if ((bad_char = BLI_utf8_invalid_byte((*str) + i, length - i)) == -1) { + if ((bad_char = BLI_str_utf8_invalid_byte((*str) + i, length - i)) == -1) { memcpy(newstr + mi, (*str) + i, length - i + 1); break; } @@ -1660,7 +1660,7 @@ void txt_insert_buf(Text *text, const char *in_buffer) /* Read the first line (or as close as possible */ while (buffer[i] && buffer[i] != '\n') { - txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &i)); + txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, len, &i)); } if (buffer[i] == '\n') { @@ -1682,7 +1682,7 @@ void txt_insert_buf(Text *text, const char *in_buffer) } else { for (j = i - l; j < i && j < len;) { - txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &j)); + txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, len, &j)); } break; } @@ -1888,8 +1888,9 @@ void txt_delete_char(Text *text) } } else { /* Just deleting a char */ - size_t c_len = 0; - c = BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &c_len); + size_t c_len = text->curc; + c = BLI_str_utf8_as_unicode_step(text->curl->line, text->curl->len, &c_len); + c_len -= text->curc; UNUSED_VARS(c); memmove(text->curl->line + text->curc, @@ -1937,9 +1938,11 @@ void txt_backspace_char(Text *text) txt_pop_sel(text); } else { /* Just backspacing a char */ - size_t c_len = 0; const char *prev = BLI_str_prev_char_utf8(text->curl->line + text->curc); - c = BLI_str_utf8_as_unicode_and_size(prev, &c_len); + size_t c_len = prev - text->curl->line; + c = BLI_str_utf8_as_unicode_step(text->curl->line, text->curl->len, &c_len); + c_len -= prev - text->curl->line; + UNUSED_VARS(c); /* source and destination overlap, don't use memcpy() */ @@ -2053,7 +2056,9 @@ bool txt_replace_char(Text *text, unsigned int add) return txt_add_char(text, add); } - del = BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &del_size); + del_size = text->curc; + del = BLI_str_utf8_as_unicode_step(text->curl->line, text->curl->len, &del_size); + del_size -= text->curc; UNUSED_VARS(del); add_size = BLI_str_utf8_from_unicode(add, ch); diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 323da7473b5..a20c918c517 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -1248,7 +1248,7 @@ static void flush_ffmpeg(AVCodecContext *c, AVStream *stream, AVFormatContext *o packet->stream_index = stream->index; av_packet_rescale_ts(packet, c->time_base, stream->time_base); # ifdef FFMPEG_USE_DURATION_WORKAROUND - my_guess_pkt_duration(context->outfile, stream, packet); + my_guess_pkt_duration(outfile, stream, packet); # endif int write_ret = av_interleaved_write_frame(outfile, packet); diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h index e877503e835..9b54f780296 100644 --- a/source/blender/blenlib/BLI_math_base.h +++ b/source/blender/blenlib/BLI_math_base.h @@ -172,6 +172,9 @@ MINLINE size_t clamp_z(size_t value, size_t min, size_t max); MINLINE int compare_ff(float a, float b, const float max_diff); MINLINE int compare_ff_relative(float a, float b, const float max_diff, const int max_ulps); +MINLINE bool compare_threshold_relative(const float value1, + const float value2, + const float thresh); MINLINE float signf(float f); MINLINE int signum_i_ex(float a, float eps); @@ -196,6 +199,8 @@ MINLINE unsigned int log2_ceil_u(unsigned int x); MINLINE int divide_round_i(int a, int b); MINLINE int mod_i(int i, int n); +MINLINE float round_to_even(float f); + MINLINE signed char round_fl_to_char(float a); MINLINE unsigned char round_fl_to_uchar(float a); MINLINE short round_fl_to_short(float a); diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h index 65d9d7863c3..b97c8748ca4 100644 --- a/source/blender/blenlib/BLI_string_utf8.h +++ b/source/blender/blenlib/BLI_string_utf8.h @@ -31,20 +31,21 @@ char *BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t ATTR_NONNULL(); size_t BLI_strncpy_utf8_rlen(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL(); -ptrdiff_t BLI_utf8_invalid_byte(const char *str, size_t length) ATTR_NONNULL(); -int BLI_utf8_invalid_strip(char *str, size_t length) ATTR_NONNULL(); +ptrdiff_t BLI_str_utf8_invalid_byte(const char *str, size_t length) ATTR_NONNULL(); +int BLI_str_utf8_invalid_strip(char *str, size_t length) ATTR_NONNULL(); /* warning, can return -1 on bad chars */ int BLI_str_utf8_size(const char *p) ATTR_NONNULL(); int BLI_str_utf8_size_safe(const char *p) ATTR_NONNULL(); /* copied from glib */ unsigned int BLI_str_utf8_as_unicode(const char *p) ATTR_NONNULL(); -unsigned int BLI_str_utf8_as_unicode_and_size(const char *__restrict p, size_t *__restrict index) - ATTR_NONNULL(); -unsigned int BLI_str_utf8_as_unicode_and_size_safe(const char *__restrict p, - size_t *__restrict index) ATTR_NONNULL(); -unsigned int BLI_str_utf8_as_unicode_step(const char *__restrict p, size_t *__restrict index) - ATTR_NONNULL(); +unsigned int BLI_str_utf8_as_unicode_step(const char *__restrict p, + size_t p_len, + size_t *__restrict index) ATTR_NONNULL(1, 3); +unsigned int BLI_str_utf8_as_unicode_step_or_error(const char *__restrict p, + size_t p_len, + size_t *__restrict index) ATTR_NONNULL(1, 3); + size_t BLI_str_utf8_from_unicode(unsigned int c, char *outbuf); size_t BLI_str_utf8_as_utf32(char32_t *__restrict dst_w, const char *__restrict src_c, diff --git a/source/blender/blenlib/intern/filereader_zstd.c b/source/blender/blenlib/intern/filereader_zstd.c index 785a40cd1a1..55ce32713d9 100644 --- a/source/blender/blenlib/intern/filereader_zstd.c +++ b/source/blender/blenlib/intern/filereader_zstd.c @@ -79,7 +79,7 @@ static bool zstd_read_seek_table(ZstdReader *zstd) if (base->seek(base, -5, SEEK_END) < 0 || base->read(base, &flags, 1) != 1) { return false; } - /* Bit 7 indicates checksums. Bits 5 and 6 must be zero. */ + /* Bit 7 indicates check-sums. Bits 5 and 6 must be zero. */ bool has_checksums = (flags & 0x80); if (flags & 0x60) { return false; @@ -134,7 +134,7 @@ static bool zstd_read_seek_table(ZstdReader *zstd) zstd->seek.compressed_ofs[num_frames] = compressed_ofs; zstd->seek.uncompressed_ofs[num_frames] = uncompressed_ofs; - /* Seek to the end of the previous frame for the following BHead frame detection. */ + /* Seek to the end of the previous frame for the following #BHead frame detection. */ if (seek_frame_start != compressed_ofs || base->seek(base, seek_frame_start, SEEK_SET) < 0) { MEM_freeN(zstd->seek.compressed_ofs); MEM_freeN(zstd->seek.uncompressed_ofs); @@ -178,7 +178,7 @@ static const char *zstd_ensure_cache(ZstdReader *zstd, int frame) return zstd->seek.cached_content; } - /* Cached frame doesn't match, so discard it and cache the wanted one onstead. */ + /* Cached frame doesn't match, so discard it and cache the wanted one instead. */ MEM_SAFE_FREE(zstd->seek.cached_content); size_t compressed_size = zstd->seek.compressed_ofs[frame + 1] - zstd->seek.compressed_ofs[frame]; diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c index a8b50b66f5f..e1e3aa273b5 100644 --- a/source/blender/blenlib/intern/freetypefont.c +++ b/source/blender/blenlib/intern/freetypefont.c @@ -302,7 +302,7 @@ static VFontData *objfnt_to_ftvfontdata(PackedFile *pf) /* Get the name. */ if (face->family_name) { BLI_snprintf(vfd->name, sizeof(vfd->name), "%s %s", face->family_name, face->style_name); - BLI_utf8_invalid_strip(vfd->name, strlen(vfd->name)); + BLI_str_utf8_invalid_strip(vfd->name, strlen(vfd->name)); } /* Select a character map. */ diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c index a80c495ecf3..49f9faf1704 100644 --- a/source/blender/blenlib/intern/math_base_inline.c +++ b/source/blender/blenlib/intern/math_base_inline.c @@ -363,6 +363,14 @@ MINLINE signed char round_db_to_char_clamp(double a){ #undef _round_clamp_fl_impl #undef _round_clamp_db_impl +/** + * Round to closest even number, halfway cases are rounded away from zero. + */ +MINLINE float round_to_even(float f) +{ + return roundf(f * 0.5f) * 2.0f; +} + /* integer division that rounds 0.5 up, particularly useful for color blending * with integers, to avoid gradual darkening when rounding down */ MINLINE int divide_round_i(int a, int b) @@ -648,6 +656,18 @@ MINLINE int compare_ff_relative(float a, float b, const float max_diff, const in return ((ua.i < 0) != (ub.i < 0)) ? 0 : (abs(ua.i - ub.i) <= max_ulps) ? 1 : 0; } +MINLINE bool compare_threshold_relative(const float value1, const float value2, const float thresh) +{ + const float abs_diff = fabsf(value1 - value2); + /* Avoid letting the threshold get too small just because the values happen to be close to zero. + */ + if (fabsf(value2) < 1) { + return abs_diff > thresh; + } + /* Using relative threshold in general. */ + return abs_diff > thresh * fabsf(value2); +} + MINLINE float signf(float f) { return (f < 0.0f) ? -1.0f : 1.0f; diff --git a/source/blender/blenlib/intern/string_cursor_utf8.c b/source/blender/blenlib/intern/string_cursor_utf8.c index 90fde02b11f..59b9f4eeca0 100644 --- a/source/blender/blenlib/intern/string_cursor_utf8.c +++ b/source/blender/blenlib/intern/string_cursor_utf8.c @@ -101,11 +101,14 @@ static eStrCursorDelimType cursor_delim_type_unicode(const uint uch) return STRCUR_DELIM_ALPHANUMERIC; /* Not quite true, but ok for now */ } -static eStrCursorDelimType cursor_delim_type_utf8(const char *ch_utf8) +static eStrCursorDelimType cursor_delim_type_utf8(const char *ch_utf8, + const size_t ch_utf8_len, + const int pos) { /* for full unicode support we really need to have large lookup tables to figure * out what's what in every possible char set - and python, glib both have these. */ - uint uch = BLI_str_utf8_as_unicode(ch_utf8); + size_t index = (size_t)pos; + uint uch = BLI_str_utf8_as_unicode_step_or_error(ch_utf8, ch_utf8_len, &index); return cursor_delim_type_unicode(uch); } @@ -157,14 +160,16 @@ void BLI_str_cursor_step_utf8(const char *str, } if (jump != STRCUR_JUMP_NONE) { - const eStrCursorDelimType delim_type = (*pos) < maxlen ? cursor_delim_type_utf8(&str[*pos]) : - STRCUR_DELIM_NONE; + const eStrCursorDelimType delim_type = (*pos) < maxlen ? + cursor_delim_type_utf8(str, maxlen, *pos) : + STRCUR_DELIM_NONE; /* jump between special characters (/,\,_,-, etc.), * look at function cursor_delim_type() for complete * list of special character, ctr -> */ while ((*pos) < maxlen) { if (BLI_str_cursor_step_next_utf8(str, maxlen, pos)) { - if ((jump != STRCUR_JUMP_ALL) && (delim_type != cursor_delim_type_utf8(&str[*pos]))) { + if ((jump != STRCUR_JUMP_ALL) && + (delim_type != cursor_delim_type_utf8(str, maxlen, *pos))) { break; } } @@ -184,7 +189,7 @@ void BLI_str_cursor_step_utf8(const char *str, if (jump != STRCUR_JUMP_NONE) { const eStrCursorDelimType delim_type = (*pos) > 0 ? - cursor_delim_type_utf8(&str[(*pos) - 1]) : + cursor_delim_type_utf8(str, maxlen, *pos - 1) : STRCUR_DELIM_NONE; /* jump between special characters (/,\,_,-, etc.), * look at function cursor_delim_type() for complete @@ -192,7 +197,8 @@ void BLI_str_cursor_step_utf8(const char *str, while ((*pos) > 0) { const int pos_prev = *pos; if (BLI_str_cursor_step_prev_utf8(str, maxlen, pos)) { - if ((jump != STRCUR_JUMP_ALL) && (delim_type != cursor_delim_type_utf8(&str[*pos]))) { + if ((jump != STRCUR_JUMP_ALL) && + (delim_type != cursor_delim_type_utf8(str, maxlen, (size_t)*pos))) { /* left only: compensate for index/change in direction */ if ((pos_orig - (*pos)) >= 1) { *pos = pos_prev; diff --git a/source/blender/blenlib/intern/string_search.cc b/source/blender/blenlib/intern/string_search.cc index 25a13674932..a466c124073 100644 --- a/source/blender/blenlib/intern/string_search.cc +++ b/source/blender/blenlib/intern/string_search.cc @@ -71,12 +71,12 @@ int damerau_levenshtein_distance(StringRef a, StringRef b) for (const int i : IndexRange(size_a)) { v2[0] = (i + 1) * deletion_cost; - const uint32_t unicode_a = BLI_str_utf8_as_unicode_and_size(a.data() + offset_a, &offset_a); + const uint32_t unicode_a = BLI_str_utf8_as_unicode_step(a.data(), a.size(), &offset_a); uint32_t prev_unicode_b; size_t offset_b = 0; for (const int j : IndexRange(size_b)) { - const uint32_t unicode_b = BLI_str_utf8_as_unicode_and_size(b.data() + offset_b, &offset_b); + const uint32_t unicode_b = BLI_str_utf8_as_unicode_step(b.data(), b.size(), &offset_b); /* Check how costly the different operations would be and pick the cheapest - the one with * minimal cost. */ @@ -202,8 +202,8 @@ static bool match_word_initials(StringRef query, int first_found_word_index = -1; while (query_index < query.size()) { - const uint query_unicode = BLI_str_utf8_as_unicode_and_size(query.data() + query_index, - &query_index); + const uint query_unicode = BLI_str_utf8_as_unicode_step( + query.data(), query.size(), &query_index); while (true) { /* We are at the end of words, no complete match has been found yet. */ if (word_index >= words.size()) { @@ -226,8 +226,8 @@ static bool match_word_initials(StringRef query, StringRef word = words[word_index]; /* Try to match the current character with the current word. */ if (static_cast<int>(char_index) < word.size()) { - const uint32_t char_unicode = BLI_str_utf8_as_unicode_and_size(word.data() + char_index, - &char_index); + const uint32_t char_unicode = BLI_str_utf8_as_unicode_step( + word.data(), word.size(), &char_index); if (query_unicode == char_unicode) { r_word_is_matched[word_index] = true; if (first_found_word_index == -1) { @@ -368,8 +368,9 @@ void extract_normalized_words(StringRef str, size_t word_start = 0; size_t offset = 0; while (offset < str_size_in_bytes) { - size_t size = 0; - uint32_t unicode = BLI_str_utf8_as_unicode_and_size(str.data() + offset, &size); + size_t size = offset; + uint32_t unicode = BLI_str_utf8_as_unicode_step(str.data(), str.size(), &size); + size -= offset; if (is_separator(unicode)) { if (is_in_word) { r_words.append( diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c index 19ff8764259..cc6a192f6ba 100644 --- a/source/blender/blenlib/intern/string_utf8.c +++ b/source/blender/blenlib/intern/string_utf8.c @@ -70,7 +70,7 @@ static const size_t utf8_skip_data[256] = { * * \return the offset of the first invalid byte. */ -ptrdiff_t BLI_utf8_invalid_byte(const char *str, size_t length) +ptrdiff_t BLI_str_utf8_invalid_byte(const char *str, size_t length) { const unsigned char *p, *perr, *pend = (const unsigned char *)str + length; unsigned char c; @@ -200,14 +200,14 @@ utf8_error: * * \return number of stripped bytes. */ -int BLI_utf8_invalid_strip(char *str, size_t length) +int BLI_str_utf8_invalid_strip(char *str, size_t length) { ptrdiff_t bad_char; int tot = 0; BLI_assert(str[length] == '\0'); - while ((bad_char = BLI_utf8_invalid_byte(str, length)) != -1) { + while ((bad_char = BLI_str_utf8_invalid_byte(str, length)) != -1) { str += bad_char; length -= (size_t)(bad_char + 1); @@ -546,85 +546,64 @@ uint BLI_str_utf8_as_unicode(const char *p) return result; } -/* variant that increments the length */ -uint BLI_str_utf8_as_unicode_and_size(const char *__restrict p, size_t *__restrict index) +/** + * UTF8 decoding that steps over the index (unless an error is encountered). + * + * \param p: The text to step over. + * \param p_len: The length of `p`. + * \param index: Index of `p` to step over. + * \return the code-point or #BLI_UTF8_ERR if there is a decoding error. + * + * \note The behavior for clipped text (where `p_len` limits decoding trailing bytes) + * must have the same behavior is encountering a nil byte, + * so functions that only use the first part of a string has matching behavior to functions + * that null terminate the text. + */ +uint BLI_str_utf8_as_unicode_step_or_error(const char *__restrict p, + const size_t p_len, + size_t *__restrict index) { int i, len; uint mask = 0; uint result; - const unsigned char c = (unsigned char)*p; + const unsigned char c = (unsigned char)*(p += *index); + + BLI_assert(*index < p_len); + BLI_assert(c != '\0'); UTF8_COMPUTE(c, mask, len, -1); - if (UNLIKELY(len == -1)) { + if (UNLIKELY(len == -1) || (*index + (size_t)len > p_len)) { return BLI_UTF8_ERR; } UTF8_GET(result, p, i, mask, len, BLI_UTF8_ERR); - *index += (size_t)len; - return result; -} - -uint BLI_str_utf8_as_unicode_and_size_safe(const char *__restrict p, size_t *__restrict index) -{ - int i, len; - uint mask = 0; - uint result; - const unsigned char c = (unsigned char)*p; - - UTF8_COMPUTE(c, mask, len, -1); - if (UNLIKELY(len == -1)) { - *index += 1; - return c; + if (UNLIKELY(result == BLI_UTF8_ERR)) { + return BLI_UTF8_ERR; } - UTF8_GET(result, p, i, mask, len, BLI_UTF8_ERR); *index += (size_t)len; + BLI_assert(*index <= p_len); return result; } /** - * Another variant that steps over the index. - * \note currently this also falls back to latin1 for text drawing. + * UTF8 decoding that steps over the index (unless an error is encountered). + * + * \param p: The text to step over. + * \param p_len: The length of `p`. + * \param index: Index of `p` to step over. + * \return the code-point `(p + *index)` if there is a decoding error. + * + * \note Falls back to `LATIN1` for text drawing. */ -uint BLI_str_utf8_as_unicode_step(const char *__restrict p, size_t *__restrict index) +uint BLI_str_utf8_as_unicode_step(const char *__restrict p, + const size_t p_len, + size_t *__restrict index) { - int i, len; - uint mask = 0; - uint result; - unsigned char c; - - p += *index; - c = (unsigned char)*p; - - UTF8_COMPUTE(c, mask, len, -1); - if (UNLIKELY(len == -1)) { - /* when called with NULL end, result will never be NULL, - * checks for a NULL character */ - const char *p_next = BLI_str_find_next_char_utf8(p, NULL); - /* will never return the same pointer unless '\0', - * eternal loop is prevented */ - *index += (size_t)(p_next - p); - return BLI_UTF8_ERR; - } - - /* this is tricky since there are a few ways we can bail out of bad unicode - * values, 3 possible solutions. */ -#if 0 - UTF8_GET(result, p, i, mask, len, BLI_UTF8_ERR); -#elif 1 - /* WARNING: this is NOT part of glib, or supported by similar functions. - * this is added for text drawing because some filepaths can have latin1 - * characters */ - UTF8_GET(result, p, i, mask, len, BLI_UTF8_ERR); - if (result == BLI_UTF8_ERR) { - len = 1; - result = *p; + uint result = BLI_str_utf8_as_unicode_step_or_error(p, p_len, index); + if (UNLIKELY(result == BLI_UTF8_ERR)) { + result = (uint)p[*index]; + *index += 1; } - /* end warning! */ -#else - /* without a fallback like '?', text drawing will stop on this value */ - UTF8_GET(result, p, i, mask, len, '?'); -#endif - - *index += (size_t)len; + BLI_assert(*index <= p_len); return result; } @@ -696,16 +675,23 @@ size_t BLI_str_utf8_as_utf32(char32_t *__restrict dst_w, memset(dst_w, 0xff, sizeof(*dst_w) * maxncpy); #endif - while (*src_c && len != maxlen) { - size_t step = 0; - uint unicode = BLI_str_utf8_as_unicode_and_size(src_c, &step); + const size_t src_c_len = strlen(src_c); + const char *src_c_end = src_c + src_c_len; + size_t index = 0; + while ((index < src_c_len) && (len != maxlen)) { + const uint unicode = BLI_str_utf8_as_unicode_step_or_error(src_c, src_c_len, &index); if (unicode != BLI_UTF8_ERR) { *dst_w = unicode; - src_c += step; } else { *dst_w = '?'; - src_c = BLI_str_find_next_char_utf8(src_c, NULL); + const char *src_c_next = BLI_str_find_next_char_utf8(src_c + index, src_c_end); + if (src_c_next != NULL) { + index = (size_t)(src_c_next - src_c); + } + else { + index += 1; + } } dst_w++; len++; @@ -810,6 +796,7 @@ char *BLI_str_find_next_char_utf8(const char *p, const char *end) { if (*p) { if (end) { + BLI_assert(end >= p); for (++p; p < end && (*p & 0xc0) == 0x80; p++) { /* do nothing */ } @@ -884,7 +871,9 @@ size_t BLI_str_partition_ex_utf8(const char *str, index = 0; *sep >= str && (!end || *sep < end) && **sep != '\0'; *sep = (char *)(from_right ? BLI_str_find_prev_char_utf8(str, *sep) : str + index)) { - const uint c = BLI_str_utf8_as_unicode_and_size(*sep, &index); + size_t index_ofs = 0; + const uint c = BLI_str_utf8_as_unicode_step_or_error(*sep, (size_t)(end - *sep), &index_ofs); + index += index_ofs; if (c == BLI_UTF8_ERR) { *suf = *sep = NULL; diff --git a/source/blender/blenlib/tests/BLI_string_utf8_test.cc b/source/blender/blenlib/tests/BLI_string_utf8_test.cc index 9ddc372e6d1..b25f2310e1e 100644 --- a/source/blender/blenlib/tests/BLI_string_utf8_test.cc +++ b/source/blender/blenlib/tests/BLI_string_utf8_test.cc @@ -2,6 +2,7 @@ #include "testing/testing.h" +#include "BLI_rand.h" #include "BLI_string.h" #include "BLI_string_utf8.h" #include "BLI_utildefines.h" @@ -11,7 +12,8 @@ * quite their share of lines, they deserved their own file. */ /* -------------------------------------------------------------------- */ -/* tests */ +/** \name Test #BLI_str_utf8_invalid_strip + * \{ */ /* Breaking strings is confusing here, prefer over-long lines. */ /* clang-format off */ @@ -266,7 +268,7 @@ static const char *utf8_invalid_tests[][3] = { }; /* clang-format on */ -/* BLI_utf8_invalid_strip (and indirectly, BLI_utf8_invalid_byte). */ +/* BLI_str_utf8_invalid_strip (and indirectly, BLI_str_utf8_invalid_byte). */ TEST(string, Utf8InvalidBytes) { for (int i = 0; utf8_invalid_tests[i][0] != nullptr; i++) { @@ -277,10 +279,117 @@ TEST(string, Utf8InvalidBytes) char buff[80]; memcpy(buff, tst, sizeof(buff)); - const int num_errors_found = BLI_utf8_invalid_strip(buff, sizeof(buff) - 1); + const int num_errors_found = BLI_str_utf8_invalid_strip(buff, sizeof(buff) - 1); printf("[%02d] -> [%02d] \"%s\" -> \"%s\"\n", num_errors, num_errors_found, tst, buff); EXPECT_EQ(num_errors_found, num_errors); EXPECT_STREQ(buff, tst_stripped); } } + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Test #BLI_str_utf8_as_unicode_step + * \{ */ + +static size_t utf8_as_char32(const char *str, const char str_len, char32_t *r_result) +{ + size_t i = 0, result_len = 0; + while ((i < str_len) && (str[i] != '\0')) { + char32_t c = BLI_str_utf8_as_unicode_step(str, str_len, &i); + if (c != BLI_UTF8_ERR) { + r_result[result_len++] = c; + } + } + return i; +} + +template<size_t Size, size_t SizeWithPadding> +void utf8_as_char32_test_compare_with_pad_bytes(const char utf8_src[Size]) +{ + char utf8_src_with_pad[SizeWithPadding] = {0}; + + memcpy(utf8_src_with_pad, utf8_src, Size); + + char32_t unicode_dst_a[Size], unicode_dst_b[Size]; + + memset(unicode_dst_a, 0xff, sizeof(unicode_dst_a)); + const size_t index_a = utf8_as_char32(utf8_src, Size, unicode_dst_a); + + /* Test with padded and un-padded size, + * to ensure that extra available space doesn't yield a different result. */ + for (int pass = 0; pass < 2; pass++) { + memset(unicode_dst_b, 0xff, sizeof(unicode_dst_b)); + const size_t index_b = utf8_as_char32( + utf8_src_with_pad, pass ? Size : SizeWithPadding, unicode_dst_b); + + /* Check the resulting content matches. */ + EXPECT_EQ_ARRAY(unicode_dst_a, unicode_dst_b, Size); + /* Check the index of the source strings match. */ + EXPECT_EQ(index_a, index_b); + } +} + +template<size_t Size> void utf8_as_char32_test_compare(const char utf8_src[Size]) +{ + /* Note that 7 is a little arbitrary, + * chosen since it's the maximum length of multi-byte character + 1 + * to account for any errors that read past null bytes. */ + utf8_as_char32_test_compare_with_pad_bytes<Size, Size + 1>(utf8_src); + utf8_as_char32_test_compare_with_pad_bytes<Size, Size + 7>(utf8_src); +} + +template<size_t Size> void utf8_as_char32_test_at_buffer_size() +{ + char utf8_src[Size]; + + /* Test uniform bytes, also with offsets ascending & descending. */ + for (int i = 0; i <= 0xff; i++) { + memset(utf8_src, i, sizeof(utf8_src)); + utf8_as_char32_test_compare<Size>(utf8_src); + + /* Offset trailing bytes up and down in steps of 1, 2, 4 .. etc. */ + if (Size > 1) { + for (int mul = 1; mul < 256; mul *= 2) { + for (int ofs = 1; ofs < (int)Size; ofs++) { + utf8_src[ofs] = (char)(i + (ofs * mul)); + } + utf8_as_char32_test_compare<Size>(utf8_src); + + for (int ofs = 1; ofs < (int)Size; ofs++) { + utf8_src[ofs] = (char)(i - (ofs * mul)); + } + utf8_as_char32_test_compare<Size>(utf8_src); + } + } + } + + /* Random bytes. */ + RNG *rng = BLI_rng_new(1); + for (int i = 0; i < 256; i++) { + BLI_rng_get_char_n(rng, utf8_src, sizeof(utf8_src)); + utf8_as_char32_test_compare<Size>(utf8_src); + } + BLI_rng_free(rng); +} + +TEST(string, Utf8AsUnicodeStep) +{ + + /* Run tests at different buffer sizes. */ + utf8_as_char32_test_at_buffer_size<1>(); + utf8_as_char32_test_at_buffer_size<2>(); + utf8_as_char32_test_at_buffer_size<3>(); + utf8_as_char32_test_at_buffer_size<4>(); + utf8_as_char32_test_at_buffer_size<5>(); + utf8_as_char32_test_at_buffer_size<6>(); + utf8_as_char32_test_at_buffer_size<7>(); + utf8_as_char32_test_at_buffer_size<8>(); + utf8_as_char32_test_at_buffer_size<9>(); + utf8_as_char32_test_at_buffer_size<10>(); + utf8_as_char32_test_at_buffer_size<11>(); + utf8_as_char32_test_at_buffer_size<12>(); +} + +/** \} */ diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index eb01bfbfb9c..72572b05ef6 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -805,5 +805,18 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } FOREACH_NODETREE_END; + + /* Disable Fade Inactive Overlay by default as it is redundant after introducing flash on mode + * transfer. */ + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + v3d->overlay.flag &= ~V3D_OVERLAY_FADE_INACTIVE; + } + } + } + } } } diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index ee287c65fe9..8ddcf11602a 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -328,10 +328,14 @@ set(SRC operations/COM_FastGaussianBlurOperation.h operations/COM_GammaCorrectOperation.cc operations/COM_GammaCorrectOperation.h + operations/COM_GaussianAlphaBlurBaseOperation.cc + operations/COM_GaussianAlphaBlurBaseOperation.h operations/COM_GaussianAlphaXBlurOperation.cc operations/COM_GaussianAlphaXBlurOperation.h operations/COM_GaussianAlphaYBlurOperation.cc operations/COM_GaussianAlphaYBlurOperation.h + operations/COM_GaussianBlurBaseOperation.cc + operations/COM_GaussianBlurBaseOperation.h operations/COM_GaussianBokehBlurOperation.cc operations/COM_GaussianBokehBlurOperation.h operations/COM_GaussianXBlurOperation.cc @@ -515,6 +519,8 @@ set(SRC operations/COM_ScaleOperation.h operations/COM_ScreenLensDistortionOperation.cc operations/COM_ScreenLensDistortionOperation.h + operations/COM_TransformOperation.cc + operations/COM_TransformOperation.h operations/COM_TranslateOperation.cc operations/COM_TranslateOperation.h operations/COM_WrapOperation.cc diff --git a/source/blender/compositor/COM_defines.h b/source/blender/compositor/COM_defines.h index 40a1e0da2a8..e270eeb3386 100644 --- a/source/blender/compositor/COM_defines.h +++ b/source/blender/compositor/COM_defines.h @@ -33,6 +33,8 @@ enum class eExecutionModel { FullFrame }; +enum class eDimension { X, Y }; + /** * \brief possible data types for sockets * \ingroup Model @@ -119,6 +121,8 @@ constexpr float COM_PREVIEW_SIZE = 140.f; constexpr float COM_RULE_OF_THIRDS_DIVIDER = 100.0f; constexpr float COM_BLUR_BOKEH_PIXELS = 512; +constexpr rcti COM_SINGLE_ELEM_AREA = {0, 1, 0, 1}; + constexpr IndexRange XRange(const rcti &area) { return IndexRange(area.xmin, area.xmax - area.xmin); diff --git a/source/blender/compositor/intern/COM_CompositorContext.h b/source/blender/compositor/intern/COM_CompositorContext.h index 403ec62e359..c6e83f93777 100644 --- a/source/blender/compositor/intern/COM_CompositorContext.h +++ b/source/blender/compositor/intern/COM_CompositorContext.h @@ -239,6 +239,12 @@ class CompositorContext { this->m_hasActiveOpenCLDevices = hasAvtiveOpenCLDevices; } + /** Whether it has a view with a specific name and not the default one. */ + bool has_explicit_view() const + { + return m_viewName && m_viewName[0] != '\0'; + } + /** * \brief get the active rendering view */ diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cc b/source/blender/compositor/intern/COM_MemoryBuffer.cc index 6b954072a9a..1fbf502fea6 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.cc +++ b/source/blender/compositor/intern/COM_MemoryBuffer.cc @@ -245,7 +245,9 @@ void MemoryBuffer::copy_from(const MemoryBuffer *src, void MemoryBuffer::copy_from(const uchar *src, const rcti &area) { - copy_from(src, area, 0, this->get_num_channels(), this->get_num_channels(), 0); + const int elem_stride = this->get_num_channels(); + const int row_stride = elem_stride * getWidth(); + copy_from(src, area, 0, this->get_num_channels(), elem_stride, row_stride, 0); } void MemoryBuffer::copy_from(const uchar *src, @@ -253,10 +255,18 @@ void MemoryBuffer::copy_from(const uchar *src, const int channel_offset, const int elem_size, const int elem_stride, + const int row_stride, const int to_channel_offset) { - copy_from( - src, area, channel_offset, elem_size, elem_stride, area.xmin, area.ymin, to_channel_offset); + copy_from(src, + area, + channel_offset, + elem_size, + elem_stride, + row_stride, + area.xmin, + area.ymin, + to_channel_offset); } void MemoryBuffer::copy_from(const uchar *src, @@ -264,6 +274,7 @@ void MemoryBuffer::copy_from(const uchar *src, const int channel_offset, const int elem_size, const int elem_stride, + const int row_stride, const int to_x, const int to_y, const int to_channel_offset) @@ -273,10 +284,9 @@ void MemoryBuffer::copy_from(const uchar *src, const int width = BLI_rcti_size_x(&area); const int height = BLI_rcti_size_y(&area); - const int src_row_stride = width * elem_stride; - const uchar *const src_start = src + area.ymin * src_row_stride + channel_offset; + const uchar *const src_start = src + area.ymin * row_stride + channel_offset; for (int y = 0; y < height; y++) { - const uchar *from_elem = src_start + y * src_row_stride; + const uchar *from_elem = src_start + y * row_stride + area.xmin * elem_stride; float *to_elem = &this->get_value(to_x, to_y + y, to_channel_offset); const float *row_end = to_elem + width * this->elem_stride; while (to_elem < row_end) { @@ -346,7 +356,16 @@ void MemoryBuffer::copy_from(const ImBuf *src, else if (src->rect) { const uchar *uc_buf = (uchar *)src->rect; const int elem_stride = src->channels; - copy_from(uc_buf, area, channel_offset, elem_size, elem_stride, to_x, to_y, to_channel_offset); + const int row_stride = elem_stride * src->x; + copy_from(uc_buf, + area, + channel_offset, + elem_size, + elem_stride, + row_stride, + to_x, + to_y, + to_channel_offset); if (ensure_linear_space) { colorspace_to_scene_linear(this, area, src->rect_colorspace); } @@ -405,12 +424,48 @@ void MemoryBuffer::addPixel(int x, int y, const float color[4]) } } +static void read_ewa_elem(void *userdata, int x, int y, float result[4]) +{ + const MemoryBuffer *buffer = static_cast<const MemoryBuffer *>(userdata); + buffer->read_elem_checked(x, y, result); +} + +void MemoryBuffer::read_elem_filtered( + const float x, const float y, float dx[2], float dy[2], float *out) const +{ + BLI_assert(this->m_datatype == DataType::Color); + + const float deriv[2][2] = {{dx[0], dx[1]}, {dy[0], dy[1]}}; + + float inv_width = 1.0f / (float)this->getWidth(), inv_height = 1.0f / (float)this->getHeight(); + /* TODO(sergey): Render pipeline uses normalized coordinates and derivatives, + * but compositor uses pixel space. For now let's just divide the values and + * switch compositor to normalized space for EWA later. + */ + float uv_normal[2] = {get_relative_x(x) * inv_width, get_relative_y(y) * inv_height}; + float du_normal[2] = {deriv[0][0] * inv_width, deriv[0][1] * inv_height}; + float dv_normal[2] = {deriv[1][0] * inv_width, deriv[1][1] * inv_height}; + + BLI_ewa_filter(this->getWidth(), + this->getHeight(), + false, + true, + uv_normal, + du_normal, + dv_normal, + read_ewa_elem, + const_cast<MemoryBuffer *>(this), + out); +} + +/* TODO(manzanilla): to be removed with tiled implementation. */ static void read_ewa_pixel_sampled(void *userdata, int x, int y, float result[4]) { MemoryBuffer *buffer = (MemoryBuffer *)userdata; buffer->read(result, x, y); } +/* TODO(manzanilla): to be removed with tiled implementation. */ void MemoryBuffer::readEWA(float *result, const float uv[2], const float derivatives[2][2]) { if (m_is_a_single_elem) { diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h index 310e87b6a4b..f3e15c2a495 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.h +++ b/source/blender/compositor/intern/COM_MemoryBuffer.h @@ -191,23 +191,96 @@ class MemoryBuffer { void read_elem(int x, int y, float *out) const { - memcpy(out, get_elem(x, y), m_num_channels * sizeof(float)); + memcpy(out, get_elem(x, y), get_elem_bytes_len()); + } + + void read_elem_checked(int x, int y, float *out) const + { + if (x < m_rect.xmin || x >= m_rect.xmax || y < m_rect.ymin || y >= m_rect.ymax) { + clear_elem(out); + } + else { + read_elem(x, y, out); + } + } + + void read_elem_checked(float x, float y, float *out) const + { + if (x < m_rect.xmin || x >= m_rect.xmax || y < m_rect.ymin || y >= m_rect.ymax) { + clear_elem(out); + } + else { + read_elem(x, y, out); + } + } + + void read_elem_bilinear(float x, float y, float *out) const + { + /* Only clear past +/-1 borders to be able to smooth edges. */ + if (x <= m_rect.xmin - 1.0f || x >= m_rect.xmax || y <= m_rect.ymin - 1.0f || + y >= m_rect.ymax) { + clear_elem(out); + return; + } + + if (m_is_a_single_elem) { + if (x >= m_rect.xmin && x < m_rect.xmax - 1.0f && y >= m_rect.ymin && + y < m_rect.ymax - 1.0f) { + memcpy(out, m_buffer, get_elem_bytes_len()); + return; + } + + /* Do sampling at borders to smooth edges. */ + const float last_x = getWidth() - 1.0f; + const float rel_x = get_relative_x(x); + float single_x = 0.0f; + if (rel_x < 0.0f) { + single_x = rel_x; + } + else if (rel_x > last_x) { + single_x = rel_x - last_x; + } + + const float last_y = getHeight() - 1.0f; + const float rel_y = get_relative_y(y); + float single_y = 0.0f; + if (rel_y < 0.0f) { + single_y = rel_y; + } + else if (rel_y > last_y) { + single_y = rel_y - last_y; + } + + BLI_bilinear_interpolation_fl(m_buffer, out, 1, 1, m_num_channels, single_x, single_y); + return; + } + + BLI_bilinear_interpolation_fl(m_buffer, + out, + getWidth(), + getHeight(), + m_num_channels, + get_relative_x(x), + get_relative_y(y)); } void read_elem_sampled(float x, float y, PixelSampler sampler, float *out) const { switch (sampler) { case PixelSampler::Nearest: - this->read_elem(x, y, out); + read_elem_checked(x, y, out); break; case PixelSampler::Bilinear: case PixelSampler::Bicubic: /* No bicubic. Current implementation produces fuzzy results. */ - this->readBilinear(out, x, y); + read_elem_bilinear(x, y, out); break; } } + void read_elem_filtered( + const float x, const float y, float dx[2], float dy[2], float *out) const; + /** * Get channel value at given coordinates. */ @@ -403,6 +476,8 @@ class MemoryBuffer { y = y + m_rect.ymin; } + /* TODO(manzanilla): to be removed with tiled implementation. For applying #MemoryBufferExtend + * use #wrap_pixel. */ inline void read(float *result, int x, int y, @@ -425,6 +500,7 @@ class MemoryBuffer { } } + /* TODO(manzanilla): to be removed with tiled implementation. */ inline void readNoCheck(float *result, int x, int y, @@ -507,12 +583,14 @@ class MemoryBuffer { int channel_offset, int elem_size, int elem_stride, + int row_stride, int to_channel_offset); void copy_from(const uchar *src, const rcti &area, int channel_offset, int elem_size, int elem_stride, + int row_stride, int to_x, int to_y, int to_channel_offset); @@ -582,6 +660,21 @@ class MemoryBuffer { return get_memory_width() * get_memory_height(); } + void clear_elem(float *out) const + { + memset(out, 0, this->m_num_channels * sizeof(float)); + } + + template<typename T> T get_relative_x(T x) const + { + return x - m_rect.xmin; + } + + template<typename T> T get_relative_y(T y) const + { + return y - m_rect.ymin; + } + void copy_single_elem_from(const MemoryBuffer *src, int channel_offset, int elem_size, diff --git a/source/blender/compositor/intern/COM_NodeGraph.cc b/source/blender/compositor/intern/COM_NodeGraph.cc index 205fbcc0440..1872fbcf656 100644 --- a/source/blender/compositor/intern/COM_NodeGraph.cc +++ b/source/blender/compositor/intern/COM_NodeGraph.cc @@ -248,7 +248,9 @@ void NodeGraph::add_proxies_group_inputs(bNode *b_node, bNode *b_node_io) } } -void NodeGraph::add_proxies_group_outputs(bNode *b_node, bNode *b_node_io, bool use_buffer) +void NodeGraph::add_proxies_group_outputs(const CompositorContext &context, + bNode *b_node, + bNode *b_node_io) { bNodeTree *b_group_tree = (bNodeTree *)b_node->id; BLI_assert(b_group_tree); /* should have been checked in advance */ @@ -261,7 +263,8 @@ void NodeGraph::add_proxies_group_outputs(bNode *b_node, bNode *b_node_io, bool b_sock_io = b_sock_io->next) { bNodeSocket *b_sock_group = find_b_node_output(b_node, b_sock_io->identifier); if (b_sock_group) { - if (use_buffer) { + if (context.isGroupnodeBufferEnabled() && + context.get_execution_model() == eExecutionModel::Tiled) { SocketBufferNode *buffer = new SocketBufferNode(b_node_io, b_sock_io, b_sock_group); add_node(buffer, b_group_tree, key, is_active_group); } @@ -297,7 +300,7 @@ void NodeGraph::add_proxies_group(const CompositorContext &context, } if (b_node_io->type == NODE_GROUP_OUTPUT && (b_node_io->flag & NODE_DO_OUTPUT)) { - add_proxies_group_outputs(b_node, b_node_io, context.isGroupnodeBufferEnabled()); + add_proxies_group_outputs(context, b_node, b_node_io); } } diff --git a/source/blender/compositor/intern/COM_NodeGraph.h b/source/blender/compositor/intern/COM_NodeGraph.h index 7fa01593e1e..dfcc6c2fcf9 100644 --- a/source/blender/compositor/intern/COM_NodeGraph.h +++ b/source/blender/compositor/intern/COM_NodeGraph.h @@ -107,7 +107,9 @@ class NodeGraph { bool is_active_group); void add_proxies_group_inputs(bNode *b_node, bNode *b_node_io); - void add_proxies_group_outputs(bNode *b_node, bNode *b_node_io, bool use_buffer); + void add_proxies_group_outputs(const CompositorContext &context, + bNode *b_node, + bNode *b_node_io); void add_proxies_group(const CompositorContext &context, bNode *b_node, bNodeInstanceKey key); void add_proxies_reroute(bNodeTree *b_ntree, diff --git a/source/blender/compositor/intern/COM_NodeOperation.cc b/source/blender/compositor/intern/COM_NodeOperation.cc index 575e8446abe..1b87cdf72fb 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.cc +++ b/source/blender/compositor/intern/COM_NodeOperation.cc @@ -82,8 +82,12 @@ void NodeOperation::determineResolution(unsigned int resolution[2], input.determineResolution(resolution, preferredResolution); used_resolution_index = m_resolutionInputSocketIndex; } - unsigned int temp2[2] = {resolution[0], resolution[1]}; + if (modify_determined_resolution_fn_) { + modify_determined_resolution_fn_(resolution); + } + + unsigned int temp2[2] = {resolution[0], resolution[1]}; unsigned int temp[2]; for (unsigned int index = 0; index < m_inputs.size(); index++) { if (index == used_resolution_index) { diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h index 934007d25ce..b402dc7f174 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.h +++ b/source/blender/compositor/intern/COM_NodeOperation.h @@ -287,6 +287,8 @@ class NodeOperation { */ unsigned int m_resolutionInputSocketIndex; + std::function<void(unsigned int resolution[2])> modify_determined_resolution_fn_; + /** * \brief mutex reference for very special node initializations * \note only use when you really know what you are doing. @@ -518,6 +520,15 @@ class NodeOperation { void setResolutionInputSocketIndex(unsigned int index); /** + * Set a custom function to modify determined resolution from main input just before setting it + * as preferred resolution for the other inputs. + */ + void set_determined_resolution_modifier(std::function<void(unsigned int resolution[2])> fn) + { + modify_determined_resolution_fn_ = fn; + } + + /** * \brief get the render priority of this node. * \note only applicable for output operations like ViewerOperation * \return eCompositorPriority diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cc b/source/blender/compositor/nodes/COM_CryptomatteNode.cc index 4032a655633..5835f051ce3 100644 --- a/source/blender/compositor/nodes/COM_CryptomatteNode.cc +++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cc @@ -124,6 +124,10 @@ void CryptomatteNode::input_operations_from_render_source( RenderLayer *render_layer = RE_GetRenderLayer(render_result, view_layer->name); if (render_layer) { LISTBASE_FOREACH (RenderPass *, render_pass, &render_layer->passes) { + if (context.has_explicit_view() && !STREQ(render_pass->view, context.getViewName())) { + continue; + } + const std::string combined_name = combined_layer_pass_name(render_layer, render_pass); if (blender::StringRef(combined_name).startswith(prefix)) { RenderLayersProg *op = new RenderLayersProg( diff --git a/source/blender/compositor/nodes/COM_RotateNode.cc b/source/blender/compositor/nodes/COM_RotateNode.cc index af5baa733dc..c2fd8ed5594 100644 --- a/source/blender/compositor/nodes/COM_RotateNode.cc +++ b/source/blender/compositor/nodes/COM_RotateNode.cc @@ -30,20 +30,31 @@ RotateNode::RotateNode(bNode *editorNode) : Node(editorNode) } void RotateNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const + const CompositorContext &context) const { NodeInput *inputSocket = this->getInputSocket(0); NodeInput *inputDegreeSocket = this->getInputSocket(1); NodeOutput *outputSocket = this->getOutputSocket(0); RotateOperation *operation = new RotateOperation(); - SetSamplerOperation *sampler = new SetSamplerOperation(); - sampler->setSampler((PixelSampler)this->getbNode()->custom1); - - converter.addOperation(sampler); converter.addOperation(operation); - converter.addLink(sampler->getOutputSocket(), operation->getInputSocket(0)); - converter.mapInputSocket(inputSocket, sampler->getInputSocket(0)); + PixelSampler sampler = (PixelSampler)this->getbNode()->custom1; + switch (context.get_execution_model()) { + case eExecutionModel::Tiled: { + SetSamplerOperation *sampler_op = new SetSamplerOperation(); + sampler_op->setSampler(sampler); + converter.addOperation(sampler_op); + converter.addLink(sampler_op->getOutputSocket(), operation->getInputSocket(0)); + converter.mapInputSocket(inputSocket, sampler_op->getInputSocket(0)); + break; + } + case eExecutionModel::FullFrame: { + operation->set_sampler(sampler); + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + break; + } + } + converter.mapInputSocket(inputDegreeSocket, operation->getInputSocket(1)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); } diff --git a/source/blender/compositor/nodes/COM_Stabilize2dNode.cc b/source/blender/compositor/nodes/COM_Stabilize2dNode.cc index 0262f653d1a..7b2388bebca 100644 --- a/source/blender/compositor/nodes/COM_Stabilize2dNode.cc +++ b/source/blender/compositor/nodes/COM_Stabilize2dNode.cc @@ -22,6 +22,7 @@ #include "COM_RotateOperation.h" #include "COM_ScaleOperation.h" #include "COM_SetSamplerOperation.h" +#include "COM_TransformOperation.h" #include "COM_TranslateOperation.h" #include "BKE_tracking.h" @@ -42,18 +43,12 @@ void Stabilize2dNode::convertToOperations(NodeConverter &converter, NodeInput *imageInput = this->getInputSocket(0); MovieClip *clip = (MovieClip *)editorNode->id; bool invert = (editorNode->custom2 & CMP_NODEFLAG_STABILIZE_INVERSE) != 0; + const PixelSampler sampler = (PixelSampler)editorNode->custom1; - ScaleRelativeOperation *scaleOperation = new ScaleRelativeOperation(); - scaleOperation->setSampler((PixelSampler)editorNode->custom1); - RotateOperation *rotateOperation = new RotateOperation(); - rotateOperation->setDoDegree2RadConversion(false); - TranslateOperation *translateOperation = new TranslateOperation(); MovieClipAttributeOperation *scaleAttribute = new MovieClipAttributeOperation(); MovieClipAttributeOperation *angleAttribute = new MovieClipAttributeOperation(); MovieClipAttributeOperation *xAttribute = new MovieClipAttributeOperation(); MovieClipAttributeOperation *yAttribute = new MovieClipAttributeOperation(); - SetSamplerOperation *psoperation = new SetSamplerOperation(); - psoperation->setSampler((PixelSampler)editorNode->custom1); scaleAttribute->setAttribute(MCA_SCALE); scaleAttribute->setFramenumber(context.getFramenumber()); @@ -79,38 +74,67 @@ void Stabilize2dNode::convertToOperations(NodeConverter &converter, converter.addOperation(angleAttribute); converter.addOperation(xAttribute); converter.addOperation(yAttribute); - converter.addOperation(scaleOperation); - converter.addOperation(translateOperation); - converter.addOperation(rotateOperation); - converter.addOperation(psoperation); - converter.addLink(scaleAttribute->getOutputSocket(), scaleOperation->getInputSocket(1)); - converter.addLink(scaleAttribute->getOutputSocket(), scaleOperation->getInputSocket(2)); - - converter.addLink(angleAttribute->getOutputSocket(), rotateOperation->getInputSocket(1)); - - converter.addLink(xAttribute->getOutputSocket(), translateOperation->getInputSocket(1)); - converter.addLink(yAttribute->getOutputSocket(), translateOperation->getInputSocket(2)); - - converter.mapOutputSocket(getOutputSocket(), psoperation->getOutputSocket()); - - if (invert) { - // Translate -> Rotate -> Scale. - converter.mapInputSocket(imageInput, translateOperation->getInputSocket(0)); - - converter.addLink(translateOperation->getOutputSocket(), rotateOperation->getInputSocket(0)); - converter.addLink(rotateOperation->getOutputSocket(), scaleOperation->getInputSocket(0)); - - converter.addLink(scaleOperation->getOutputSocket(), psoperation->getInputSocket(0)); - } - else { - // Scale -> Rotate -> Translate. - converter.mapInputSocket(imageInput, scaleOperation->getInputSocket(0)); - - converter.addLink(scaleOperation->getOutputSocket(), rotateOperation->getInputSocket(0)); - converter.addLink(rotateOperation->getOutputSocket(), translateOperation->getInputSocket(0)); - - converter.addLink(translateOperation->getOutputSocket(), psoperation->getInputSocket(0)); + switch (context.get_execution_model()) { + case eExecutionModel::Tiled: { + ScaleRelativeOperation *scaleOperation = new ScaleRelativeOperation(); + scaleOperation->setSampler(sampler); + RotateOperation *rotateOperation = new RotateOperation(); + rotateOperation->setDoDegree2RadConversion(false); + TranslateOperation *translateOperation = new TranslateOperation(); + SetSamplerOperation *psoperation = new SetSamplerOperation(); + psoperation->setSampler(sampler); + + converter.addOperation(scaleOperation); + converter.addOperation(translateOperation); + converter.addOperation(rotateOperation); + converter.addOperation(psoperation); + + converter.addLink(scaleAttribute->getOutputSocket(), scaleOperation->getInputSocket(1)); + converter.addLink(scaleAttribute->getOutputSocket(), scaleOperation->getInputSocket(2)); + + converter.addLink(angleAttribute->getOutputSocket(), rotateOperation->getInputSocket(1)); + + converter.addLink(xAttribute->getOutputSocket(), translateOperation->getInputSocket(1)); + converter.addLink(yAttribute->getOutputSocket(), translateOperation->getInputSocket(2)); + + converter.mapOutputSocket(getOutputSocket(), psoperation->getOutputSocket()); + + if (invert) { + // Translate -> Rotate -> Scale. + converter.mapInputSocket(imageInput, translateOperation->getInputSocket(0)); + + converter.addLink(translateOperation->getOutputSocket(), + rotateOperation->getInputSocket(0)); + converter.addLink(rotateOperation->getOutputSocket(), scaleOperation->getInputSocket(0)); + + converter.addLink(scaleOperation->getOutputSocket(), psoperation->getInputSocket(0)); + } + else { + // Scale -> Rotate -> Translate. + converter.mapInputSocket(imageInput, scaleOperation->getInputSocket(0)); + + converter.addLink(scaleOperation->getOutputSocket(), rotateOperation->getInputSocket(0)); + converter.addLink(rotateOperation->getOutputSocket(), + translateOperation->getInputSocket(0)); + + converter.addLink(translateOperation->getOutputSocket(), psoperation->getInputSocket(0)); + } + break; + } + case eExecutionModel::FullFrame: { + TransformOperation *transform_op = new TransformOperation(); + transform_op->set_sampler(sampler); + transform_op->set_convert_rotate_degree_to_rad(false); + transform_op->set_invert(invert); + converter.addOperation(transform_op); + converter.mapInputSocket(imageInput, transform_op->getInputSocket(0)); + converter.addLink(xAttribute->getOutputSocket(), transform_op->getInputSocket(1)); + converter.addLink(yAttribute->getOutputSocket(), transform_op->getInputSocket(2)); + converter.addLink(angleAttribute->getOutputSocket(), transform_op->getInputSocket(3)); + converter.addLink(scaleAttribute->getOutputSocket(), transform_op->getInputSocket(4)); + converter.mapOutputSocket(getOutputSocket(), transform_op->getOutputSocket()); + } } } diff --git a/source/blender/compositor/nodes/COM_TransformNode.cc b/source/blender/compositor/nodes/COM_TransformNode.cc index e1deaf616a4..d2fb7b54633 100644 --- a/source/blender/compositor/nodes/COM_TransformNode.cc +++ b/source/blender/compositor/nodes/COM_TransformNode.cc @@ -22,6 +22,7 @@ #include "COM_ScaleOperation.h" #include "COM_SetSamplerOperation.h" #include "COM_SetValueOperation.h" +#include "COM_TransformOperation.h" #include "COM_TranslateOperation.h" namespace blender::compositor { @@ -32,7 +33,7 @@ TransformNode::TransformNode(bNode *editorNode) : Node(editorNode) } void TransformNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const + const CompositorContext &context) const { NodeInput *imageInput = this->getInputSocket(0); NodeInput *xInput = this->getInputSocket(1); @@ -40,33 +41,51 @@ void TransformNode::convertToOperations(NodeConverter &converter, NodeInput *angleInput = this->getInputSocket(3); NodeInput *scaleInput = this->getInputSocket(4); - ScaleRelativeOperation *scaleOperation = new ScaleRelativeOperation(); - converter.addOperation(scaleOperation); + switch (context.get_execution_model()) { + case eExecutionModel::Tiled: { + ScaleRelativeOperation *scaleOperation = new ScaleRelativeOperation(); + converter.addOperation(scaleOperation); - RotateOperation *rotateOperation = new RotateOperation(); - rotateOperation->setDoDegree2RadConversion(false); - converter.addOperation(rotateOperation); + RotateOperation *rotateOperation = new RotateOperation(); + rotateOperation->setDoDegree2RadConversion(false); + converter.addOperation(rotateOperation); - TranslateOperation *translateOperation = new TranslateOperation(); - converter.addOperation(translateOperation); + TranslateOperation *translateOperation = new TranslateOperation(); + converter.addOperation(translateOperation); - SetSamplerOperation *sampler = new SetSamplerOperation(); - sampler->setSampler((PixelSampler)this->getbNode()->custom1); - converter.addOperation(sampler); + SetSamplerOperation *sampler = new SetSamplerOperation(); + sampler->setSampler((PixelSampler)this->getbNode()->custom1); + converter.addOperation(sampler); - converter.mapInputSocket(imageInput, sampler->getInputSocket(0)); - converter.addLink(sampler->getOutputSocket(), scaleOperation->getInputSocket(0)); - converter.mapInputSocket(scaleInput, scaleOperation->getInputSocket(1)); - converter.mapInputSocket(scaleInput, scaleOperation->getInputSocket(2)); // xscale = yscale + converter.mapInputSocket(imageInput, sampler->getInputSocket(0)); + converter.addLink(sampler->getOutputSocket(), scaleOperation->getInputSocket(0)); + converter.mapInputSocket(scaleInput, scaleOperation->getInputSocket(1)); + converter.mapInputSocket(scaleInput, scaleOperation->getInputSocket(2)); // xscale = yscale - converter.addLink(scaleOperation->getOutputSocket(), rotateOperation->getInputSocket(0)); - converter.mapInputSocket(angleInput, rotateOperation->getInputSocket(1)); + converter.addLink(scaleOperation->getOutputSocket(), rotateOperation->getInputSocket(0)); + converter.mapInputSocket(angleInput, rotateOperation->getInputSocket(1)); - converter.addLink(rotateOperation->getOutputSocket(), translateOperation->getInputSocket(0)); - converter.mapInputSocket(xInput, translateOperation->getInputSocket(1)); - converter.mapInputSocket(yInput, translateOperation->getInputSocket(2)); + converter.addLink(rotateOperation->getOutputSocket(), translateOperation->getInputSocket(0)); + converter.mapInputSocket(xInput, translateOperation->getInputSocket(1)); + converter.mapInputSocket(yInput, translateOperation->getInputSocket(2)); - converter.mapOutputSocket(getOutputSocket(), translateOperation->getOutputSocket()); + converter.mapOutputSocket(getOutputSocket(), translateOperation->getOutputSocket()); + break; + } + case eExecutionModel::FullFrame: { + TransformOperation *op = new TransformOperation(); + op->set_sampler((PixelSampler)this->getbNode()->custom1); + converter.addOperation(op); + + converter.mapInputSocket(imageInput, op->getInputSocket(0)); + converter.mapInputSocket(xInput, op->getInputSocket(1)); + converter.mapInputSocket(yInput, op->getInputSocket(2)); + converter.mapInputSocket(angleInput, op->getInputSocket(3)); + converter.mapInputSocket(scaleInput, op->getInputSocket(4)); + converter.mapOutputSocket(getOutputSocket(), op->getOutputSocket()); + break; + } + } } } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cc b/source/blender/compositor/operations/COM_BlurBaseOperation.cc index 8b73624ca79..058b422c4a5 100644 --- a/source/blender/compositor/operations/COM_BlurBaseOperation.cc +++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cc @@ -17,6 +17,8 @@ */ #include "COM_BlurBaseOperation.h" +#include "COM_ConstantOperation.h" + #include "BLI_math.h" #include "MEM_guardedalloc.h" @@ -36,11 +38,15 @@ BlurBaseOperation::BlurBaseOperation(DataType data_type) this->m_size = 1.0f; this->m_sizeavailable = false; this->m_extend_bounds = false; + use_variable_size_ = false; } -void BlurBaseOperation::initExecution() + +void BlurBaseOperation::init_data() { - this->m_inputProgram = this->getInputSocketReader(0); - this->m_inputSize = this->getInputSocketReader(1); + if (execution_model_ == eExecutionModel::FullFrame) { + updateSize(); + } + this->m_data.image_in_width = this->getWidth(); this->m_data.image_in_height = this->getHeight(); if (this->m_data.relative) { @@ -61,6 +67,12 @@ void BlurBaseOperation::initExecution() this->m_data.sizex = round_fl_to_int(this->m_data.percentx * 0.01f * sizex); this->m_data.sizey = round_fl_to_int(this->m_data.percenty * 0.01f * sizey); } +} + +void BlurBaseOperation::initExecution() +{ + this->m_inputProgram = this->getInputSocketReader(0); + this->m_inputSize = this->getInputSocketReader(1); QualityStepHelper::initExecution(COM_QH_MULTIPLY); } @@ -165,23 +177,82 @@ void BlurBaseOperation::setData(const NodeBlurData *data) memcpy(&m_data, data, sizeof(NodeBlurData)); } +int BlurBaseOperation::get_blur_size(eDimension dim) const +{ + switch (dim) { + case eDimension::X: + return m_data.sizex; + case eDimension::Y: + return m_data.sizey; + } + return -1; +} + void BlurBaseOperation::updateSize() { - if (!this->m_sizeavailable) { - float result[4]; - this->getInputSocketReader(1)->readSampled(result, 0, 0, PixelSampler::Nearest); - this->m_size = result[0]; - this->m_sizeavailable = true; + if (this->m_sizeavailable || use_variable_size_) { + return; } + + switch (execution_model_) { + case eExecutionModel::Tiled: { + float result[4]; + this->getInputSocketReader(1)->readSampled(result, 0, 0, PixelSampler::Nearest); + this->m_size = result[0]; + break; + } + case eExecutionModel::FullFrame: { + NodeOperation *size_input = get_input_operation(SIZE_INPUT_INDEX); + if (size_input->get_flags().is_constant_operation) { + m_size = *static_cast<ConstantOperation *>(size_input)->get_constant_elem(); + } /* Else use default. */ + break; + } + } + this->m_sizeavailable = true; } void BlurBaseOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) { - NodeOperation::determineResolution(resolution, preferredResolution); - if (this->m_extend_bounds) { - resolution[0] += 2 * this->m_size * m_data.sizex; - resolution[1] += 2 * this->m_size * m_data.sizey; + if (!m_extend_bounds) { + NodeOperation::determineResolution(resolution, preferredResolution); + return; + } + + switch (execution_model_) { + case eExecutionModel::Tiled: { + NodeOperation::determineResolution(resolution, preferredResolution); + resolution[0] += 2 * m_size * m_data.sizex; + resolution[1] += 2 * m_size * m_data.sizey; + break; + } + case eExecutionModel::FullFrame: { + /* Setting a modifier ensures all non main inputs have extended bounds as preferred + * resolution, avoiding unnecessary resolution conversions that would hide constant + * operations. */ + set_determined_resolution_modifier([=](unsigned int res[2]) { + /* Rounding to even prevents jiggling in backdrop while switching size values. */ + res[0] += round_to_even(2 * m_size * m_data.sizex); + res[1] += round_to_even(2 * m_size * m_data.sizey); + }); + NodeOperation::determineResolution(resolution, preferredResolution); + break; + } + } +} + +void BlurBaseOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + switch (input_idx) { + case 0: + r_input_area = output_area; + break; + case 1: + r_input_area = use_variable_size_ ? output_area : COM_SINGLE_ELEM_AREA; + break; } } diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.h b/source/blender/compositor/operations/COM_BlurBaseOperation.h index 7937ebd69dc..78b1e919aa6 100644 --- a/source/blender/compositor/operations/COM_BlurBaseOperation.h +++ b/source/blender/compositor/operations/COM_BlurBaseOperation.h @@ -18,7 +18,7 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" #include "COM_QualityStepHelper.h" #define MAX_GAUSSTAB_RADIUS 30000 @@ -27,10 +27,16 @@ namespace blender::compositor { -class BlurBaseOperation : public NodeOperation, public QualityStepHelper { +class BlurBaseOperation : public MultiThreadedOperation, public QualityStepHelper { private: + bool m_extend_bounds; + + protected: + static constexpr int IMAGE_INPUT_INDEX = 0; + static constexpr int SIZE_INPUT_INDEX = 1; + protected: - BlurBaseOperation(DataType data_type); + BlurBaseOperation(DataType data_type8); float *make_gausstab(float rad, int size); #ifdef BLI_HAVE_SSE2 __m128 *convert_gausstab_sse(const float *gausstab, int size); @@ -49,9 +55,11 @@ class BlurBaseOperation : public NodeOperation, public QualityStepHelper { float m_size; bool m_sizeavailable; - bool m_extend_bounds; + /* Flags for inheriting classes. */ + bool use_variable_size_; public: + virtual void init_data() override; /** * Initialize the execution */ @@ -75,8 +83,14 @@ class BlurBaseOperation : public NodeOperation, public QualityStepHelper { this->m_extend_bounds = extend_bounds; } + int get_blur_size(eDimension dim) const; + void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) override; + + virtual void get_area_of_interest(int input_idx, + const rcti &output_area, + rcti &r_input_area) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cc b/source/blender/compositor/operations/COM_BokehBlurOperation.cc index 3f98732b403..f2a43b7dbca 100644 --- a/source/blender/compositor/operations/COM_BokehBlurOperation.cc +++ b/source/blender/compositor/operations/COM_BokehBlurOperation.cc @@ -17,6 +17,8 @@ */ #include "COM_BokehBlurOperation.h" +#include "COM_ConstantOperation.h" + #include "BLI_math.h" #include "COM_OpenCLDevice.h" @@ -24,6 +26,11 @@ namespace blender::compositor { +constexpr int IMAGE_INPUT_INDEX = 0; +constexpr int BOKEH_INPUT_INDEX = 1; +constexpr int BOUNDING_BOX_INPUT_INDEX = 2; +constexpr int SIZE_INPUT_INDEX = 3; + BokehBlurOperation::BokehBlurOperation() { this->addInputSocket(DataType::Color); @@ -44,6 +51,23 @@ BokehBlurOperation::BokehBlurOperation() this->m_extend_bounds = false; } +void BokehBlurOperation::init_data() +{ + if (execution_model_ == eExecutionModel::FullFrame) { + updateSize(); + } + + NodeOperation *bokeh = get_input_operation(BOKEH_INPUT_INDEX); + const int width = bokeh->getWidth(); + const int height = bokeh->getHeight(); + + const float dimension = MIN2(width, height); + + m_bokehMidX = width / 2.0f; + m_bokehMidY = height / 2.0f; + m_bokehDimension = dimension / 2.0f; +} + void *BokehBlurOperation::initializeTileData(rcti * /*rect*/) { lockMutex(); @@ -58,18 +82,11 @@ void *BokehBlurOperation::initializeTileData(rcti * /*rect*/) void BokehBlurOperation::initExecution() { initMutex(); + this->m_inputProgram = getInputSocketReader(0); this->m_inputBokehProgram = getInputSocketReader(1); this->m_inputBoundingBoxReader = getInputSocketReader(2); - int width = this->m_inputBokehProgram->getWidth(); - int height = this->m_inputBokehProgram->getHeight(); - - float dimension = MIN2(width, height); - - this->m_bokehMidX = width / 2.0f; - this->m_bokehMidY = height / 2.0f; - this->m_bokehDimension = dimension / 2.0f; QualityStepHelper::initExecution(COM_QH_INCREASE); } @@ -225,23 +242,146 @@ void BokehBlurOperation::executeOpenCL(OpenCLDevice *device, void BokehBlurOperation::updateSize() { - if (!this->m_sizeavailable) { - float result[4]; - this->getInputSocketReader(3)->readSampled(result, 0, 0, PixelSampler::Nearest); - this->m_size = result[0]; - CLAMP(this->m_size, 0.0f, 10.0f); - this->m_sizeavailable = true; + if (this->m_sizeavailable) { + return; } + + switch (execution_model_) { + case eExecutionModel::Tiled: { + float result[4]; + this->getInputSocketReader(3)->readSampled(result, 0, 0, PixelSampler::Nearest); + this->m_size = result[0]; + CLAMP(this->m_size, 0.0f, 10.0f); + break; + } + case eExecutionModel::FullFrame: { + NodeOperation *size_input = get_input_operation(SIZE_INPUT_INDEX); + if (size_input->get_flags().is_constant_operation) { + m_size = *static_cast<ConstantOperation *>(size_input)->get_constant_elem(); + CLAMP(m_size, 0.0f, 10.0f); + } /* Else use default. */ + break; + } + } + this->m_sizeavailable = true; } void BokehBlurOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) { - NodeOperation::determineResolution(resolution, preferredResolution); - if (this->m_extend_bounds) { - const float max_dim = MAX2(resolution[0], resolution[1]); - resolution[0] += 2 * this->m_size * max_dim / 100.0f; - resolution[1] += 2 * this->m_size * max_dim / 100.0f; + if (!m_extend_bounds) { + NodeOperation::determineResolution(resolution, preferredResolution); + return; + } + + switch (execution_model_) { + case eExecutionModel::Tiled: { + NodeOperation::determineResolution(resolution, preferredResolution); + const float max_dim = MAX2(resolution[0], resolution[1]); + resolution[0] += 2 * this->m_size * max_dim / 100.0f; + resolution[1] += 2 * this->m_size * max_dim / 100.0f; + break; + } + case eExecutionModel::FullFrame: { + set_determined_resolution_modifier([=](unsigned int res[2]) { + const float max_dim = MAX2(res[0], res[1]); + /* Rounding to even prevents image jiggling in backdrop while switching size values. */ + float add_size = round_to_even(2 * this->m_size * max_dim / 100.0f); + res[0] += add_size; + res[1] += add_size; + }); + NodeOperation::determineResolution(resolution, preferredResolution); + break; + } + } +} + +void BokehBlurOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + switch (input_idx) { + case IMAGE_INPUT_INDEX: { + const float max_dim = MAX2(this->getWidth(), this->getHeight()); + const float add_size = m_size * max_dim / 100.0f; + r_input_area.xmin = output_area.xmin - add_size; + r_input_area.xmax = output_area.xmax + add_size; + r_input_area.ymin = output_area.ymin - add_size; + r_input_area.ymax = output_area.ymax + add_size; + break; + } + case BOKEH_INPUT_INDEX: { + NodeOperation *bokeh_input = getInputOperation(BOKEH_INPUT_INDEX); + r_input_area.xmin = 0; + r_input_area.xmax = bokeh_input->getWidth(); + r_input_area.ymin = 0; + r_input_area.ymax = bokeh_input->getHeight(); + break; + } + case BOUNDING_BOX_INPUT_INDEX: + r_input_area = output_area; + break; + case SIZE_INPUT_INDEX: { + r_input_area = COM_SINGLE_ELEM_AREA; + break; + } + } +} + +void BokehBlurOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const float max_dim = MAX2(this->getWidth(), this->getHeight()); + const int pixel_size = m_size * max_dim / 100.0f; + const float m = m_bokehDimension / pixel_size; + + const MemoryBuffer *image_input = inputs[IMAGE_INPUT_INDEX]; + const MemoryBuffer *bokeh_input = inputs[BOKEH_INPUT_INDEX]; + MemoryBuffer *bounding_input = inputs[BOUNDING_BOX_INPUT_INDEX]; + BuffersIterator<float> it = output->iterate_with({bounding_input}, area); + const rcti &image_rect = image_input->get_rect(); + for (; !it.is_end(); ++it) { + const int x = it.x; + const int y = it.y; + const float bounding_box = *it.in(0); + if (bounding_box <= 0.0f) { + image_input->read_elem(x, y, it.out); + continue; + } + + float color_accum[4] = {0}; + float multiplier_accum[4] = {0}; + if (pixel_size < 2) { + image_input->read_elem(x, y, color_accum); + multiplier_accum[0] = 1.0f; + multiplier_accum[1] = 1.0f; + multiplier_accum[2] = 1.0f; + multiplier_accum[3] = 1.0f; + } + const int miny = MAX2(y - pixel_size, image_rect.ymin); + const int maxy = MIN2(y + pixel_size, image_rect.ymax); + const int minx = MAX2(x - pixel_size, image_rect.xmin); + const int maxx = MIN2(x + pixel_size, image_rect.xmax); + const int step = getStep(); + const int elem_stride = image_input->elem_stride * step; + const int row_stride = image_input->row_stride * step; + const float *row_color = image_input->get_elem(minx, miny); + for (int ny = miny; ny < maxy; ny += step, row_color += row_stride) { + const float *color = row_color; + const float v = m_bokehMidY - (ny - y) * m; + for (int nx = minx; nx < maxx; nx += step, color += elem_stride) { + const float u = m_bokehMidX - (nx - x) * m; + float bokeh[4]; + bokeh_input->read_elem_checked(u, v, bokeh); + madd_v4_v4v4(color_accum, bokeh, color); + add_v4_v4(multiplier_accum, bokeh); + } + } + it.out[0] = color_accum[0] * (1.0f / multiplier_accum[0]); + it.out[1] = color_accum[1] * (1.0f / multiplier_accum[1]); + it.out[2] = color_accum[2] * (1.0f / multiplier_accum[2]); + it.out[3] = color_accum[3] * (1.0f / multiplier_accum[3]); } } diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.h b/source/blender/compositor/operations/COM_BokehBlurOperation.h index 3ce06adb5d6..59c14305393 100644 --- a/source/blender/compositor/operations/COM_BokehBlurOperation.h +++ b/source/blender/compositor/operations/COM_BokehBlurOperation.h @@ -18,12 +18,12 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" #include "COM_QualityStepHelper.h" namespace blender::compositor { -class BokehBlurOperation : public NodeOperation, public QualityStepHelper { +class BokehBlurOperation : public MultiThreadedOperation, public QualityStepHelper { private: SocketReader *m_inputProgram; SocketReader *m_inputBokehProgram; @@ -31,6 +31,7 @@ class BokehBlurOperation : public NodeOperation, public QualityStepHelper { void updateSize(); float m_size; bool m_sizeavailable; + float m_bokehMidX; float m_bokehMidY; float m_bokehDimension; @@ -39,6 +40,8 @@ class BokehBlurOperation : public NodeOperation, public QualityStepHelper { public: BokehBlurOperation(); + void init_data() override; + void *initializeTileData(rcti *rect) override; /** * The inner loop of this operation. @@ -79,6 +82,11 @@ class BokehBlurOperation : public NodeOperation, public QualityStepHelper { void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) override; + + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.cc b/source/blender/compositor/operations/COM_ChannelMatteOperation.cc index ec4331dc231..65742d0cfcc 100644 --- a/source/blender/compositor/operations/COM_ChannelMatteOperation.cc +++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.cc @@ -27,6 +27,7 @@ ChannelMatteOperation::ChannelMatteOperation() addOutputSocket(DataType::Value); this->m_inputImageProgram = nullptr; + flags.can_be_constant = true; } void ChannelMatteOperation::initExecution() @@ -121,4 +122,37 @@ void ChannelMatteOperation::executePixelSampled(float output[4], output[0] = MIN2(alpha, inColor[3]); } +void ChannelMatteOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + const float *color = it.in(0); + + /* Matte operation. */ + float alpha = color[this->m_ids[0]] - MAX2(color[this->m_ids[1]], color[this->m_ids[2]]); + + /* Flip because 0.0 is transparent, not 1.0. */ + alpha = 1.0f - alpha; + + /* Test range. */ + if (alpha > m_limit_max) { + alpha = color[3]; /* Whatever it was prior. */ + } + else if (alpha < m_limit_min) { + alpha = 0.0f; + } + else { /* Blend. */ + alpha = (alpha - m_limit_min) / m_limit_range; + } + + /* Store matte(alpha) value in [0] to go with + * COM_SetAlphaMultiplyOperation and the Value output. + */ + + /* Don't make something that was more transparent less transparent. */ + *it.out = MIN2(alpha, color[3]); + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.h b/source/blender/compositor/operations/COM_ChannelMatteOperation.h index 6e9dcccd36e..ba50105dd3b 100644 --- a/source/blender/compositor/operations/COM_ChannelMatteOperation.h +++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.h @@ -18,7 +18,7 @@ #pragma once -#include "COM_MixOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { @@ -26,7 +26,7 @@ namespace blender::compositor { * this program converts an input color to an output value. * it assumes we are in sRGB color space. */ -class ChannelMatteOperation : public NodeOperation { +class ChannelMatteOperation : public MultiThreadedOperation { private: SocketReader *m_inputImageProgram; @@ -71,6 +71,10 @@ class ChannelMatteOperation : public NodeOperation { this->m_limit_channel = nodeChroma->channel; this->m_matte_channel = custom2; } + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ChromaMatteOperation.cc b/source/blender/compositor/operations/COM_ChromaMatteOperation.cc index b7fec5f07e5..0784f266b19 100644 --- a/source/blender/compositor/operations/COM_ChromaMatteOperation.cc +++ b/source/blender/compositor/operations/COM_ChromaMatteOperation.cc @@ -29,6 +29,7 @@ ChromaMatteOperation::ChromaMatteOperation() this->m_inputImageProgram = nullptr; this->m_inputKeyProgram = nullptr; + flags.can_be_constant = true; } void ChromaMatteOperation::initExecution() @@ -110,4 +111,58 @@ void ChromaMatteOperation::executePixelSampled(float output[4], } } +void ChromaMatteOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const float acceptance = this->m_settings->t1; /* In radians. */ + const float cutoff = this->m_settings->t2; /* In radians. */ + const float gain = this->m_settings->fstrength; + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + const float *in_image = it.in(0); + const float *in_key = it.in(1); + + /* Store matte(alpha) value in [0] to go with + * #COM_SetAlphaMultiplyOperation and the Value output. */ + + /* Algorithm from book "Video Demystified", does not include the spill reduction part. */ + /* Find theta, the angle that the color space should be rotated based on key. */ + + /* Rescale to `-1.0..1.0`. */ + // const float image_Y = (in_image[0] * 2.0f) - 1.0f; // UNUSED + const float image_cb = (in_image[1] * 2.0f) - 1.0f; + const float image_cr = (in_image[2] * 2.0f) - 1.0f; + + // const float key_Y = (in_key[0] * 2.0f) - 1.0f; // UNUSED + const float key_cb = (in_key[1] * 2.0f) - 1.0f; + const float key_cr = (in_key[2] * 2.0f) - 1.0f; + + const float theta = atan2(key_cr, key_cb); + + /* Rotate the cb and cr into x/z space. */ + const float x_angle = image_cb * cosf(theta) + image_cr * sinf(theta); + const float z_angle = image_cr * cosf(theta) - image_cb * sinf(theta); + + /* If within the acceptance angle. */ + /* If kfg is <0 then the pixel is outside of the key color. */ + const float kfg = x_angle - (fabsf(z_angle) / tanf(acceptance / 2.0f)); + + if (kfg > 0.0f) { /* Found a pixel that is within key color. */ + const float beta = atan2(z_angle, x_angle); + float alpha = 1.0f - (kfg / gain); + + /* Ff beta is within the cutoff angle. */ + if (fabsf(beta) < (cutoff / 2.0f)) { + alpha = 0.0f; + } + + /* Don't make something that was more transparent less transparent. */ + it.out[0] = alpha < in_image[3] ? alpha : in_image[3]; + } + else { /* Pixel is outside key color. */ + it.out[0] = in_image[3]; /* Make pixel just as transparent as it was before. */ + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ChromaMatteOperation.h b/source/blender/compositor/operations/COM_ChromaMatteOperation.h index 48c3a785011..065349910a7 100644 --- a/source/blender/compositor/operations/COM_ChromaMatteOperation.h +++ b/source/blender/compositor/operations/COM_ChromaMatteOperation.h @@ -18,7 +18,7 @@ #pragma once -#include "COM_MixOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { @@ -26,7 +26,7 @@ namespace blender::compositor { * this program converts an input color to an output value. * it assumes we are in sRGB color space. */ -class ChromaMatteOperation : public NodeOperation { +class ChromaMatteOperation : public MultiThreadedOperation { private: NodeChroma *m_settings; SocketReader *m_inputImageProgram; @@ -50,6 +50,10 @@ class ChromaMatteOperation : public NodeOperation { { this->m_settings = nodeChroma; } + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorMatteOperation.cc b/source/blender/compositor/operations/COM_ColorMatteOperation.cc index ddfbf415d9c..dec6571f217 100644 --- a/source/blender/compositor/operations/COM_ColorMatteOperation.cc +++ b/source/blender/compositor/operations/COM_ColorMatteOperation.cc @@ -29,6 +29,7 @@ ColorMatteOperation::ColorMatteOperation() this->m_inputImageProgram = nullptr; this->m_inputKeyProgram = nullptr; + flags.can_be_constant = true; } void ColorMatteOperation::initExecution() @@ -82,4 +83,40 @@ void ColorMatteOperation::executePixelSampled(float output[4], } } +void ColorMatteOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const float hue = m_settings->t1; + const float sat = m_settings->t2; + const float val = m_settings->t3; + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + const float *in_color = it.in(0); + const float *in_key = it.in(1); + + /* Store matte(alpha) value in [0] to go with + * COM_SetAlphaMultiplyOperation and the Value output. + */ + + float h_wrap; + if ( + /* Do hue last because it needs to wrap, and does some more checks. */ + + /* #sat */ (fabsf(in_color[1] - in_key[1]) < sat) && + /* #val */ (fabsf(in_color[2] - in_key[2]) < val) && + + /* Multiply by 2 because it wraps on both sides of the hue, + * otherwise 0.5 would key all hue's. */ + + /* #hue */ + ((h_wrap = 2.0f * fabsf(in_color[0] - in_key[0])) < hue || (2.0f - h_wrap) < hue)) { + it.out[0] = 0.0f; /* Make transparent. */ + } + + else { /* Pixel is outside key color. */ + it.out[0] = in_color[3]; /* Make pixel just as transparent as it was before. */ + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorMatteOperation.h b/source/blender/compositor/operations/COM_ColorMatteOperation.h index 439a3b0741d..49d06e62e65 100644 --- a/source/blender/compositor/operations/COM_ColorMatteOperation.h +++ b/source/blender/compositor/operations/COM_ColorMatteOperation.h @@ -18,7 +18,7 @@ #pragma once -#include "COM_MixOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { @@ -26,7 +26,7 @@ namespace blender::compositor { * this program converts an input color to an output value. * it assumes we are in sRGB color space. */ -class ColorMatteOperation : public NodeOperation { +class ColorMatteOperation : public MultiThreadedOperation { private: NodeChroma *m_settings; SocketReader *m_inputImageProgram; @@ -50,6 +50,10 @@ class ColorMatteOperation : public NodeOperation { { this->m_settings = nodeChroma; } + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorRampOperation.cc b/source/blender/compositor/operations/COM_ColorRampOperation.cc index 0ee65a6529e..6c1b23ea731 100644 --- a/source/blender/compositor/operations/COM_ColorRampOperation.cc +++ b/source/blender/compositor/operations/COM_ColorRampOperation.cc @@ -29,6 +29,7 @@ ColorRampOperation::ColorRampOperation() this->m_inputProgram = nullptr; this->m_colorBand = nullptr; + this->flags.can_be_constant = true; } void ColorRampOperation::initExecution() { @@ -51,4 +52,13 @@ void ColorRampOperation::deinitExecution() this->m_inputProgram = nullptr; } +void ColorRampOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + BKE_colorband_evaluate(m_colorBand, *it.in(0), it.out); + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorRampOperation.h b/source/blender/compositor/operations/COM_ColorRampOperation.h index d32af9bea24..ab64b9928fd 100644 --- a/source/blender/compositor/operations/COM_ColorRampOperation.h +++ b/source/blender/compositor/operations/COM_ColorRampOperation.h @@ -18,12 +18,12 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" #include "DNA_texture_types.h" namespace blender::compositor { -class ColorRampOperation : public NodeOperation { +class ColorRampOperation : public MultiThreadedOperation { private: /** * Cached reference to the inputProgram @@ -53,6 +53,10 @@ class ColorRampOperation : public NodeOperation { { this->m_colorBand = colorBand; } + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorSpillOperation.cc b/source/blender/compositor/operations/COM_ColorSpillOperation.cc index 7dc7e2775fc..4b0e0520b75 100644 --- a/source/blender/compositor/operations/COM_ColorSpillOperation.cc +++ b/source/blender/compositor/operations/COM_ColorSpillOperation.cc @@ -32,6 +32,7 @@ ColorSpillOperation::ColorSpillOperation() this->m_inputFacReader = nullptr; this->m_spillChannel = 1; // GREEN this->m_spillMethod = 0; + flags.can_be_constant = true; } void ColorSpillOperation::initExecution() @@ -118,4 +119,36 @@ void ColorSpillOperation::executePixelSampled(float output[4], } } +void ColorSpillOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + const float *color = it.in(0); + const float factor = MIN2(1.0f, *it.in(1)); + + float map; + switch (m_spillMethod) { + case 0: /* simple */ + map = factor * + (color[m_spillChannel] - (m_settings->limscale * color[m_settings->limchan])); + break; + default: /* average */ + map = factor * (color[m_spillChannel] - + (m_settings->limscale * AVG(color[m_channel2], color[m_channel3]))); + break; + } + + if (map > 0.0f) { + it.out[0] = color[0] + m_rmut * (m_settings->uspillr * map); + it.out[1] = color[1] + m_gmut * (m_settings->uspillg * map); + it.out[2] = color[2] + m_bmut * (m_settings->uspillb * map); + it.out[3] = color[3]; + } + else { + copy_v4_v4(it.out, color); + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorSpillOperation.h b/source/blender/compositor/operations/COM_ColorSpillOperation.h index 9b82e720527..6a5e688c160 100644 --- a/source/blender/compositor/operations/COM_ColorSpillOperation.h +++ b/source/blender/compositor/operations/COM_ColorSpillOperation.h @@ -18,7 +18,7 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { @@ -26,7 +26,7 @@ namespace blender::compositor { * this program converts an input color to an output value. * it assumes we are in sRGB color space. */ -class ColorSpillOperation : public NodeOperation { +class ColorSpillOperation : public MultiThreadedOperation { protected: NodeColorspill *m_settings; SocketReader *m_inputImageReader; @@ -65,6 +65,10 @@ class ColorSpillOperation : public NodeOperation { } float calculateMapValue(float fac, float *input); + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ConvertOperation.cc b/source/blender/compositor/operations/COM_ConvertOperation.cc index 384936533c7..d377903efea 100644 --- a/source/blender/compositor/operations/COM_ConvertOperation.cc +++ b/source/blender/compositor/operations/COM_ConvertOperation.cc @@ -27,6 +27,7 @@ namespace blender::compositor { ConvertBaseOperation::ConvertBaseOperation() { this->m_inputOperation = nullptr; + this->flags.can_be_constant = true; } void ConvertBaseOperation::initExecution() @@ -39,6 +40,14 @@ void ConvertBaseOperation::deinitExecution() this->m_inputOperation = nullptr; } +void ConvertBaseOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + BuffersIterator<float> it = output->iterate_with(inputs, area); + update_memory_buffer_partial(it); +} + /* ******** Value to Color ******** */ ConvertValueToColorOperation::ConvertValueToColorOperation() : ConvertBaseOperation() @@ -58,6 +67,14 @@ void ConvertValueToColorOperation::executePixelSampled(float output[4], output[3] = 1.0f; } +void ConvertValueToColorOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + it.out[0] = it.out[1] = it.out[2] = *it.in(0); + it.out[3] = 1.0f; + } +} + /* ******** Color to Value ******** */ ConvertColorToValueOperation::ConvertColorToValueOperation() : ConvertBaseOperation() @@ -76,6 +93,14 @@ void ConvertColorToValueOperation::executePixelSampled(float output[4], output[0] = (inputColor[0] + inputColor[1] + inputColor[2]) / 3.0f; } +void ConvertColorToValueOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + const float *in = it.in(0); + it.out[0] = (in[0] + in[1] + in[2]) / 3.0f; + } +} + /* ******** Color to BW ******** */ ConvertColorToBWOperation::ConvertColorToBWOperation() : ConvertBaseOperation() @@ -94,6 +119,13 @@ void ConvertColorToBWOperation::executePixelSampled(float output[4], output[0] = IMB_colormanagement_get_luminance(inputColor); } +void ConvertColorToBWOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + it.out[0] = IMB_colormanagement_get_luminance(it.in(0)); + } +} + /* ******** Color to Vector ******** */ ConvertColorToVectorOperation::ConvertColorToVectorOperation() : ConvertBaseOperation() @@ -112,6 +144,13 @@ void ConvertColorToVectorOperation::executePixelSampled(float output[4], copy_v3_v3(output, color); } +void ConvertColorToVectorOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + copy_v3_v3(it.out, it.in(0)); + } +} + /* ******** Value to Vector ******** */ ConvertValueToVectorOperation::ConvertValueToVectorOperation() : ConvertBaseOperation() @@ -130,6 +169,13 @@ void ConvertValueToVectorOperation::executePixelSampled(float output[4], output[0] = output[1] = output[2] = value; } +void ConvertValueToVectorOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + it.out[0] = it.out[1] = it.out[2] = *it.in(0); + } +} + /* ******** Vector to Color ******** */ ConvertVectorToColorOperation::ConvertVectorToColorOperation() : ConvertBaseOperation() @@ -147,6 +193,14 @@ void ConvertVectorToColorOperation::executePixelSampled(float output[4], output[3] = 1.0f; } +void ConvertVectorToColorOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + copy_v3_v3(it.out, it.in(0)); + it.out[3] = 1.0f; + } +} + /* ******** Vector to Value ******** */ ConvertVectorToValueOperation::ConvertVectorToValueOperation() : ConvertBaseOperation() @@ -165,6 +219,14 @@ void ConvertVectorToValueOperation::executePixelSampled(float output[4], output[0] = (input[0] + input[1] + input[2]) / 3.0f; } +void ConvertVectorToValueOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + const float *in = it.in(0); + it.out[0] = (in[0] + in[1] + in[2]) / 3.0f; + } +} + /* ******** RGB to YCC ******** */ ConvertRGBToYCCOperation::ConvertRGBToYCCOperation() : ConvertBaseOperation() @@ -207,6 +269,18 @@ void ConvertRGBToYCCOperation::executePixelSampled(float output[4], output[3] = inputColor[3]; } +void ConvertRGBToYCCOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + const float *in = it.in(0); + rgb_to_ycc(in[0], in[1], in[2], &it.out[0], &it.out[1], &it.out[2], this->m_mode); + + /* Normalize for viewing (#rgb_to_ycc returns 0-255 values). */ + mul_v3_fl(it.out, 1.0f / 255.0f); + it.out[3] = in[3]; + } +} + /* ******** YCC to RGB ******** */ ConvertYCCToRGBOperation::ConvertYCCToRGBOperation() : ConvertBaseOperation() @@ -253,6 +327,22 @@ void ConvertYCCToRGBOperation::executePixelSampled(float output[4], output[3] = inputColor[3]; } +void ConvertYCCToRGBOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + const float *in = it.in(0); + /* Multiply by 255 to un-normalize (#ycc_to_rgb needs input values in 0-255 range). */ + ycc_to_rgb(in[0] * 255.0f, + in[1] * 255.0f, + in[2] * 255.0f, + &it.out[0], + &it.out[1], + &it.out[2], + this->m_mode); + it.out[3] = in[3]; + } +} + /* ******** RGB to YUV ******** */ ConvertRGBToYUVOperation::ConvertRGBToYUVOperation() : ConvertBaseOperation() @@ -278,6 +368,15 @@ void ConvertRGBToYUVOperation::executePixelSampled(float output[4], output[3] = inputColor[3]; } +void ConvertRGBToYUVOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + const float *in = it.in(0); + rgb_to_yuv(in[0], in[1], in[2], &it.out[0], &it.out[1], &it.out[2], BLI_YUV_ITU_BT709); + it.out[3] = in[3]; + } +} + /* ******** YUV to RGB ******** */ ConvertYUVToRGBOperation::ConvertYUVToRGBOperation() : ConvertBaseOperation() @@ -303,6 +402,15 @@ void ConvertYUVToRGBOperation::executePixelSampled(float output[4], output[3] = inputColor[3]; } +void ConvertYUVToRGBOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + const float *in = it.in(0); + yuv_to_rgb(in[0], in[1], in[2], &it.out[0], &it.out[1], &it.out[2], BLI_YUV_ITU_BT709); + it.out[3] = in[3]; + } +} + /* ******** RGB to HSV ******** */ ConvertRGBToHSVOperation::ConvertRGBToHSVOperation() : ConvertBaseOperation() @@ -322,6 +430,15 @@ void ConvertRGBToHSVOperation::executePixelSampled(float output[4], output[3] = inputColor[3]; } +void ConvertRGBToHSVOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + const float *in = it.in(0); + rgb_to_hsv_v(in, it.out); + it.out[3] = in[3]; + } +} + /* ******** HSV to RGB ******** */ ConvertHSVToRGBOperation::ConvertHSVToRGBOperation() : ConvertBaseOperation() @@ -344,6 +461,18 @@ void ConvertHSVToRGBOperation::executePixelSampled(float output[4], output[3] = inputColor[3]; } +void ConvertHSVToRGBOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + const float *in = it.in(0); + hsv_to_rgb_v(in, it.out); + it.out[0] = max_ff(it.out[0], 0.0f); + it.out[1] = max_ff(it.out[1], 0.0f); + it.out[2] = max_ff(it.out[2], 0.0f); + it.out[3] = in[3]; + } +} + /* ******** Premul to Straight ******** */ ConvertPremulToStraightOperation::ConvertPremulToStraightOperation() : ConvertBaseOperation() @@ -363,6 +492,13 @@ void ConvertPremulToStraightOperation::executePixelSampled(float output[4], copy_v4_v4(output, converted); } +void ConvertPremulToStraightOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + copy_v4_v4(it.out, ColorSceneLinear4f<eAlpha::Premultiplied>(it.in(0)).unpremultiply_alpha()); + } +} + /* ******** Straight to Premul ******** */ ConvertStraightToPremulOperation::ConvertStraightToPremulOperation() : ConvertBaseOperation() @@ -382,6 +518,13 @@ void ConvertStraightToPremulOperation::executePixelSampled(float output[4], copy_v4_v4(output, converted); } +void ConvertStraightToPremulOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + copy_v4_v4(it.out, ColorSceneLinear4f<eAlpha::Straight>(it.in(0)).premultiply_alpha()); + } +} + /* ******** Separate Channels ******** */ SeparateChannelOperation::SeparateChannelOperation() @@ -410,6 +553,15 @@ void SeparateChannelOperation::executePixelSampled(float output[4], output[0] = input[this->m_channel]; } +void SeparateChannelOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + it.out[0] = it.in(0)[this->m_channel]; + } +} + /* ******** Combine Channels ******** */ CombineChannelsOperation::CombineChannelsOperation() @@ -466,4 +618,16 @@ void CombineChannelsOperation::executePixelSampled(float output[4], } } +void CombineChannelsOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + it.out[0] = *it.in(0); + it.out[1] = *it.in(1); + it.out[2] = *it.in(2); + it.out[3] = *it.in(3); + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ConvertOperation.h b/source/blender/compositor/operations/COM_ConvertOperation.h index 7a726e35c7c..0334959ae7e 100644 --- a/source/blender/compositor/operations/COM_ConvertOperation.h +++ b/source/blender/compositor/operations/COM_ConvertOperation.h @@ -18,11 +18,11 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { -class ConvertBaseOperation : public NodeOperation { +class ConvertBaseOperation : public MultiThreadedOperation { protected: SocketReader *m_inputOperation; @@ -31,6 +31,13 @@ class ConvertBaseOperation : public NodeOperation { void initExecution() override; void deinitExecution() override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) final; + + protected: + virtual void update_memory_buffer_partial(BuffersIterator<float> &it) = 0; }; class ConvertValueToColorOperation : public ConvertBaseOperation { @@ -38,6 +45,9 @@ class ConvertValueToColorOperation : public ConvertBaseOperation { ConvertValueToColorOperation(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class ConvertColorToValueOperation : public ConvertBaseOperation { @@ -45,6 +55,9 @@ class ConvertColorToValueOperation : public ConvertBaseOperation { ConvertColorToValueOperation(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class ConvertColorToBWOperation : public ConvertBaseOperation { @@ -52,6 +65,9 @@ class ConvertColorToBWOperation : public ConvertBaseOperation { ConvertColorToBWOperation(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class ConvertColorToVectorOperation : public ConvertBaseOperation { @@ -59,6 +75,9 @@ class ConvertColorToVectorOperation : public ConvertBaseOperation { ConvertColorToVectorOperation(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class ConvertValueToVectorOperation : public ConvertBaseOperation { @@ -66,6 +85,9 @@ class ConvertValueToVectorOperation : public ConvertBaseOperation { ConvertValueToVectorOperation(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class ConvertVectorToColorOperation : public ConvertBaseOperation { @@ -73,6 +95,9 @@ class ConvertVectorToColorOperation : public ConvertBaseOperation { ConvertVectorToColorOperation(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class ConvertVectorToValueOperation : public ConvertBaseOperation { @@ -80,6 +105,9 @@ class ConvertVectorToValueOperation : public ConvertBaseOperation { ConvertVectorToValueOperation(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class ConvertRGBToYCCOperation : public ConvertBaseOperation { @@ -94,6 +122,9 @@ class ConvertRGBToYCCOperation : public ConvertBaseOperation { /** Set the YCC mode */ void setMode(int mode); + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class ConvertYCCToRGBOperation : public ConvertBaseOperation { @@ -108,6 +139,9 @@ class ConvertYCCToRGBOperation : public ConvertBaseOperation { /** Set the YCC mode */ void setMode(int mode); + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class ConvertRGBToYUVOperation : public ConvertBaseOperation { @@ -115,6 +149,9 @@ class ConvertRGBToYUVOperation : public ConvertBaseOperation { ConvertRGBToYUVOperation(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class ConvertYUVToRGBOperation : public ConvertBaseOperation { @@ -122,6 +159,9 @@ class ConvertYUVToRGBOperation : public ConvertBaseOperation { ConvertYUVToRGBOperation(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class ConvertRGBToHSVOperation : public ConvertBaseOperation { @@ -129,6 +169,9 @@ class ConvertRGBToHSVOperation : public ConvertBaseOperation { ConvertRGBToHSVOperation(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class ConvertHSVToRGBOperation : public ConvertBaseOperation { @@ -136,6 +179,9 @@ class ConvertHSVToRGBOperation : public ConvertBaseOperation { ConvertHSVToRGBOperation(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class ConvertPremulToStraightOperation : public ConvertBaseOperation { @@ -143,6 +189,9 @@ class ConvertPremulToStraightOperation : public ConvertBaseOperation { ConvertPremulToStraightOperation(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class ConvertStraightToPremulOperation : public ConvertBaseOperation { @@ -150,9 +199,12 @@ class ConvertStraightToPremulOperation : public ConvertBaseOperation { ConvertStraightToPremulOperation(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; -class SeparateChannelOperation : public NodeOperation { +class SeparateChannelOperation : public MultiThreadedOperation { private: SocketReader *m_inputOperation; int m_channel; @@ -168,9 +220,13 @@ class SeparateChannelOperation : public NodeOperation { { this->m_channel = channel; } + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; -class CombineChannelsOperation : public NodeOperation { +class CombineChannelsOperation : public MultiThreadedOperation { private: SocketReader *m_inputChannel1Operation; SocketReader *m_inputChannel2Operation; @@ -183,6 +239,10 @@ class CombineChannelsOperation : public NodeOperation { void initExecution() override; void deinitExecution() override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_CropOperation.cc b/source/blender/compositor/operations/COM_CropOperation.cc index f12d93bc8d3..12833660fcb 100644 --- a/source/blender/compositor/operations/COM_CropOperation.cc +++ b/source/blender/compositor/operations/COM_CropOperation.cc @@ -95,6 +95,22 @@ void CropOperation::executePixelSampled(float output[4], float x, float y, Pixel } } +void CropOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + rcti crop_area; + BLI_rcti_init(&crop_area, m_xmin, m_xmax, m_ymin, m_ymax); + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + if (BLI_rcti_isect_pt(&crop_area, it.x, it.y)) { + copy_v4_v4(it.out, it.in(0)); + } + else { + zero_v4(it.out); + } + } +} + CropImageOperation::CropImageOperation() : CropBaseOperation() { /* pass */ @@ -114,6 +130,18 @@ bool CropImageOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } +void CropImageOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + BLI_assert(input_idx == 0); + UNUSED_VARS_NDEBUG(input_idx); + r_input_area.xmax = output_area.xmax + this->m_xmin; + r_input_area.xmin = output_area.xmin + this->m_xmin; + r_input_area.ymax = output_area.ymax + this->m_ymin; + r_input_area.ymin = output_area.ymin + this->m_ymin; +} + void CropImageOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) { @@ -136,4 +164,21 @@ void CropImageOperation::executePixelSampled(float output[4], } } +void CropImageOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + rcti op_area; + BLI_rcti_init(&op_area, 0, getWidth(), 0, getHeight()); + const MemoryBuffer *input = inputs[0]; + for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) { + if (BLI_rcti_isect_pt(&op_area, it.x, it.y)) { + input->read_elem_checked(it.x + this->m_xmin, it.y + this->m_ymin, it.out); + } + else { + zero_v4(it.out); + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_CropOperation.h b/source/blender/compositor/operations/COM_CropOperation.h index acdff79a77c..57caa4e5834 100644 --- a/source/blender/compositor/operations/COM_CropOperation.h +++ b/source/blender/compositor/operations/COM_CropOperation.h @@ -18,11 +18,11 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { -class CropBaseOperation : public NodeOperation { +class CropBaseOperation : public MultiThreadedOperation { protected: SocketReader *m_inputOperation; NodeTwoXYs *m_settings; @@ -53,6 +53,10 @@ class CropOperation : public CropBaseOperation { public: CropOperation(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; class CropImageOperation : public CropBaseOperation { @@ -65,6 +69,11 @@ class CropImageOperation : public CropBaseOperation { void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_CryptomatteOperation.cc b/source/blender/compositor/operations/COM_CryptomatteOperation.cc index 1a86fadad76..02e7c5607d8 100644 --- a/source/blender/compositor/operations/COM_CryptomatteOperation.cc +++ b/source/blender/compositor/operations/COM_CryptomatteOperation.cc @@ -71,4 +71,34 @@ void CryptomatteOperation::executePixel(float output[4], int x, int y, void *dat } } +void CryptomatteOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + zero_v4(it.out); + for (int i = 0; i < it.get_num_inputs(); i++) { + const float *input = it.in(i); + if (i == 0) { + /* Write the front-most object as false color for picking. */ + it.out[0] = input[0]; + uint32_t m3hash; + ::memcpy(&m3hash, &input[0], sizeof(uint32_t)); + /* Since the red channel is likely to be out of display range, + * setting green and blue gives more meaningful images. */ + it.out[1] = ((float)(m3hash << 8) / (float)UINT32_MAX); + it.out[2] = ((float)(m3hash << 16) / (float)UINT32_MAX); + } + for (const float hash : m_objectIndex) { + if (input[0] == hash) { + it.out[3] += input[1]; + } + if (input[2] == hash) { + it.out[3] += input[3]; + } + } + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_CryptomatteOperation.h b/source/blender/compositor/operations/COM_CryptomatteOperation.h index 1b91358d228..f1bf4cdf624 100644 --- a/source/blender/compositor/operations/COM_CryptomatteOperation.h +++ b/source/blender/compositor/operations/COM_CryptomatteOperation.h @@ -18,11 +18,11 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { -class CryptomatteOperation : public NodeOperation { +class CryptomatteOperation : public MultiThreadedOperation { private: Vector<float> m_objectIndex; @@ -35,6 +35,10 @@ class CryptomatteOperation : public NodeOperation { void executePixel(float output[4], int x, int y, void *data) override; void addObjectIndex(float objectIndex); + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc index 0acdfc1651f..31714b03b06 100644 --- a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc +++ b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc @@ -29,6 +29,7 @@ DifferenceMatteOperation::DifferenceMatteOperation() this->m_inputImage1Program = nullptr; this->m_inputImage2Program = nullptr; + flags.can_be_constant = true; } void DifferenceMatteOperation::initExecution() @@ -86,4 +87,44 @@ void DifferenceMatteOperation::executePixelSampled(float output[4], } } +void DifferenceMatteOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + const float *color1 = it.in(0); + const float *color2 = it.in(1); + + float difference = (fabsf(color2[0] - color1[0]) + fabsf(color2[1] - color1[1]) + + fabsf(color2[2] - color1[2])); + + /* Average together the distances. */ + difference = difference / 3.0f; + + const float tolerance = m_settings->t1; + const float falloff = m_settings->t2; + + /* Make 100% transparent. */ + if (difference <= tolerance) { + it.out[0] = 0.0f; + } + /* In the falloff region, make partially transparent. */ + else if (difference <= falloff + tolerance) { + difference = difference - tolerance; + const float alpha = difference / falloff; + /* Only change if more transparent than before. */ + if (alpha < color1[3]) { + it.out[0] = alpha; + } + else { /* Leave as before. */ + it.out[0] = color1[3]; + } + } + else { + /* Foreground object. */ + it.out[0] = color1[3]; + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DifferenceMatteOperation.h b/source/blender/compositor/operations/COM_DifferenceMatteOperation.h index d3963fee1c1..0a86535d946 100644 --- a/source/blender/compositor/operations/COM_DifferenceMatteOperation.h +++ b/source/blender/compositor/operations/COM_DifferenceMatteOperation.h @@ -18,7 +18,7 @@ #pragma once -#include "COM_MixOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { @@ -26,7 +26,7 @@ namespace blender::compositor { * this program converts an input color to an output value. * it assumes we are in sRGB color space. */ -class DifferenceMatteOperation : public NodeOperation { +class DifferenceMatteOperation : public MultiThreadedOperation { private: NodeChroma *m_settings; SocketReader *m_inputImage1Program; @@ -50,6 +50,10 @@ class DifferenceMatteOperation : public NodeOperation { { this->m_settings = nodeChroma; } + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.cc b/source/blender/compositor/operations/COM_DisplaceOperation.cc index 9f3f5cfe489..a4c01fda7ca 100644 --- a/source/blender/compositor/operations/COM_DisplaceOperation.cc +++ b/source/blender/compositor/operations/COM_DisplaceOperation.cc @@ -32,20 +32,30 @@ DisplaceOperation::DisplaceOperation() this->flags.complex = true; this->m_inputColorProgram = nullptr; - this->m_inputVectorProgram = nullptr; - this->m_inputScaleXProgram = nullptr; - this->m_inputScaleYProgram = nullptr; } void DisplaceOperation::initExecution() { this->m_inputColorProgram = this->getInputSocketReader(0); - this->m_inputVectorProgram = this->getInputSocketReader(1); - this->m_inputScaleXProgram = this->getInputSocketReader(2); - this->m_inputScaleYProgram = this->getInputSocketReader(3); + NodeOperation *vector = this->getInputSocketReader(1); + NodeOperation *scale_x = this->getInputSocketReader(2); + NodeOperation *scale_y = this->getInputSocketReader(3); + if (execution_model_ == eExecutionModel::Tiled) { + vector_read_fn_ = [=](float x, float y, float *out) { + vector->readSampled(out, x, y, PixelSampler::Bilinear); + }; + scale_x_read_fn_ = [=](float x, float y, float *out) { + scale_x->readSampled(out, x, y, PixelSampler::Nearest); + }; + scale_y_read_fn_ = [=](float x, float y, float *out) { + scale_y->readSampled(out, x, y, PixelSampler::Nearest); + }; + } this->m_width_x4 = this->getWidth() * 4; this->m_height_x4 = this->getHeight() * 4; + input_vector_width_ = vector->getWidth(); + input_vector_height_ = vector->getHeight(); } void DisplaceOperation::executePixelSampled(float output[4], @@ -69,8 +79,8 @@ void DisplaceOperation::executePixelSampled(float output[4], bool DisplaceOperation::read_displacement( float x, float y, float xscale, float yscale, const float origin[2], float &r_u, float &r_v) { - float width = m_inputVectorProgram->getWidth(); - float height = m_inputVectorProgram->getHeight(); + float width = input_vector_width_; + float height = input_vector_height_; if (x < 0.0f || x >= width || y < 0.0f || y >= height) { r_u = 0.0f; r_v = 0.0f; @@ -78,7 +88,7 @@ bool DisplaceOperation::read_displacement( } float col[4]; - m_inputVectorProgram->readSampled(col, x, y, PixelSampler::Bilinear); + vector_read_fn_(x, y, col); r_u = origin[0] - col[0] * xscale; r_v = origin[1] - col[1] * yscale; return true; @@ -90,9 +100,9 @@ void DisplaceOperation::pixelTransform(const float xy[2], float r_uv[2], float r float uv[2]; /* temporary variables for derivative estimation */ int num; - m_inputScaleXProgram->readSampled(col, xy[0], xy[1], PixelSampler::Nearest); + scale_x_read_fn_(xy[0], xy[1], col); float xs = col[0]; - m_inputScaleYProgram->readSampled(col, xy[0], xy[1], PixelSampler::Nearest); + scale_y_read_fn_(xy[0], xy[1], col); float ys = col[0]; /* clamp x and y displacement to triple image resolution - * to prevent hangs from huge values mistakenly plugged in eg. z buffers */ @@ -146,9 +156,9 @@ void DisplaceOperation::pixelTransform(const float xy[2], float r_uv[2], float r void DisplaceOperation::deinitExecution() { this->m_inputColorProgram = nullptr; - this->m_inputVectorProgram = nullptr; - this->m_inputScaleXProgram = nullptr; - this->m_inputScaleYProgram = nullptr; + vector_read_fn_ = nullptr; + scale_x_read_fn_ = nullptr; + scale_y_read_fn_ = nullptr; } bool DisplaceOperation::determineDependingAreaOfInterest(rcti *input, @@ -195,4 +205,61 @@ bool DisplaceOperation::determineDependingAreaOfInterest(rcti *input, return false; } +void DisplaceOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + switch (input_idx) { + case 0: { + r_input_area.xmin = 0; + r_input_area.ymin = 0; + r_input_area.xmax = getInputOperation(input_idx)->getWidth(); + r_input_area.ymax = getInputOperation(input_idx)->getHeight(); + break; + } + case 1: { + r_input_area = output_area; + expand_area_for_sampler(r_input_area, PixelSampler::Bilinear); + break; + } + default: { + r_input_area = output_area; + break; + } + } +} + +void DisplaceOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output), + const rcti &UNUSED(area), + Span<MemoryBuffer *> inputs) +{ + MemoryBuffer *vector = inputs[1]; + MemoryBuffer *scale_x = inputs[2]; + MemoryBuffer *scale_y = inputs[3]; + vector_read_fn_ = [=](float x, float y, float *out) { vector->read_elem_bilinear(x, y, out); }; + scale_x_read_fn_ = [=](float x, float y, float *out) { scale_x->read_elem_checked(x, y, out); }; + scale_y_read_fn_ = [=](float x, float y, float *out) { scale_y->read_elem_checked(x, y, out); }; +} + +void DisplaceOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input_color = inputs[0]; + for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) { + const float xy[2] = {(float)it.x, (float)it.y}; + float uv[2]; + float deriv[2][2]; + + pixelTransform(xy, uv, deriv); + if (is_zero_v2(deriv[0]) && is_zero_v2(deriv[1])) { + input_color->read_elem_bilinear(uv[0], uv[1], it.out); + } + else { + /* EWA filtering (without nearest it gets blurry with NO distortion). */ + input_color->read_elem_filtered(uv[0], uv[1], deriv[0], deriv[1], it.out); + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.h b/source/blender/compositor/operations/COM_DisplaceOperation.h index fd82692f687..5be914ab672 100644 --- a/source/blender/compositor/operations/COM_DisplaceOperation.h +++ b/source/blender/compositor/operations/COM_DisplaceOperation.h @@ -18,23 +18,27 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { -class DisplaceOperation : public NodeOperation { +class DisplaceOperation : public MultiThreadedOperation { private: /** * Cached reference to the inputProgram */ SocketReader *m_inputColorProgram; - SocketReader *m_inputVectorProgram; - SocketReader *m_inputScaleXProgram; - SocketReader *m_inputScaleYProgram; float m_width_x4; float m_height_x4; + int input_vector_width_; + int input_vector_height_; + + std::function<void(float x, float y, float *out)> vector_read_fn_; + std::function<void(float x, float y, float *out)> scale_x_read_fn_; + std::function<void(float x, float y, float *out)> scale_y_read_fn_; + public: DisplaceOperation(); @@ -62,6 +66,14 @@ class DisplaceOperation : public NodeOperation { */ void deinitExecution() override; + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + void update_memory_buffer_started(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; + private: bool read_displacement( float x, float y, float xscale, float yscale, const float origin[2], float &r_u, float &r_v); diff --git a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc index f4b77f5d32c..e1c531bd49e 100644 --- a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc +++ b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc @@ -132,4 +132,56 @@ bool DisplaceSimpleOperation::determineDependingAreaOfInterest(rcti *input, return false; } +void DisplaceSimpleOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + switch (input_idx) { + case 0: { + r_input_area.xmin = 0; + r_input_area.ymin = 0; + r_input_area.xmax = getInputOperation(input_idx)->getWidth(); + r_input_area.ymax = getInputOperation(input_idx)->getHeight(); + break; + } + default: { + r_input_area = output_area; + break; + } + } +} + +void DisplaceSimpleOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const float width = this->getWidth(); + const float height = this->getHeight(); + const MemoryBuffer *input_color = inputs[0]; + for (BuffersIterator<float> it = output->iterate_with(inputs.drop_front(1), area); !it.is_end(); + ++it) { + float scale_x = *it.in(1); + float scale_y = *it.in(2); + + /* Clamp x and y displacement to triple image resolution - + * to prevent hangs from huge values mistakenly plugged in eg. z buffers. */ + CLAMP(scale_x, -m_width_x4, m_width_x4); + CLAMP(scale_y, -m_height_x4, m_height_x4); + + /* Main displacement in pixel space. */ + const float *vector = it.in(0); + const float p_dx = vector[0] * scale_x; + const float p_dy = vector[1] * scale_y; + + /* Displaced pixel in uv coords, for image sampling. */ + /* Clamp nodes to avoid glitches. */ + float u = it.x - p_dx + 0.5f; + float v = it.y - p_dy + 0.5f; + CLAMP(u, 0.0f, width - 1.0f); + CLAMP(v, 0.0f, height - 1.0f); + + input_color->read_elem_checked(u, v, it.out); + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.h b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.h index 15e6fcd0523..99f52155466 100644 --- a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.h +++ b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.h @@ -18,11 +18,11 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { -class DisplaceSimpleOperation : public NodeOperation { +class DisplaceSimpleOperation : public MultiThreadedOperation { private: /** * Cached reference to the inputProgram @@ -59,6 +59,11 @@ class DisplaceSimpleOperation : public NodeOperation { * Deinitialize the execution */ void deinitExecution() override; + + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc index 1b3403cbb29..8155ff769a0 100644 --- a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc +++ b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc @@ -29,6 +29,7 @@ DistanceRGBMatteOperation::DistanceRGBMatteOperation() this->m_inputImageProgram = nullptr; this->m_inputKeyProgram = nullptr; + flags.can_be_constant = true; } void DistanceRGBMatteOperation::initExecution() @@ -43,7 +44,7 @@ void DistanceRGBMatteOperation::deinitExecution() this->m_inputKeyProgram = nullptr; } -float DistanceRGBMatteOperation::calculateDistance(float key[4], float image[4]) +float DistanceRGBMatteOperation::calculateDistance(const float key[4], const float image[4]) { return len_v3v3(key, image); } @@ -93,4 +94,43 @@ void DistanceRGBMatteOperation::executePixelSampled(float output[4], } } +void DistanceRGBMatteOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + const float *in_image = it.in(0); + const float *in_key = it.in(1); + + float distance = this->calculateDistance(in_key, in_image); + const float tolerance = this->m_settings->t1; + const float falloff = this->m_settings->t2; + + /* Store matte(alpha) value in [0] to go with + * COM_SetAlphaMultiplyOperation and the Value output. + */ + + /* Make 100% transparent. */ + if (distance < tolerance) { + it.out[0] = 0.0f; + } + /* In the falloff region, make partially transparent. */ + else if (distance < falloff + tolerance) { + distance = distance - tolerance; + const float alpha = distance / falloff; + /* Only change if more transparent than before. */ + if (alpha < in_image[3]) { + it.out[0] = alpha; + } + else { /* Leave as before. */ + it.out[0] = in_image[3]; + } + } + else { + /* Leave as before. */ + it.out[0] = in_image[3]; + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.h b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.h index 6fe603233b7..ba6682214ae 100644 --- a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.h +++ b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.h @@ -18,7 +18,7 @@ #pragma once -#include "COM_MixOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { @@ -26,13 +26,13 @@ namespace blender::compositor { * this program converts an input color to an output value. * it assumes we are in sRGB color space. */ -class DistanceRGBMatteOperation : public NodeOperation { +class DistanceRGBMatteOperation : public MultiThreadedOperation { protected: NodeChroma *m_settings; SocketReader *m_inputImageProgram; SocketReader *m_inputKeyProgram; - virtual float calculateDistance(float key[4], float image[4]); + virtual float calculateDistance(const float key[4], const float image[4]); public: /** @@ -52,6 +52,10 @@ class DistanceRGBMatteOperation : public NodeOperation { { this->m_settings = nodeChroma; } + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc index 597545dd706..50e473ea5b3 100644 --- a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc +++ b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc @@ -21,7 +21,7 @@ namespace blender::compositor { -float DistanceYCCMatteOperation::calculateDistance(float key[4], float image[4]) +float DistanceYCCMatteOperation::calculateDistance(const float key[4], const float image[4]) { /* only measure the second 2 values */ return len_v2v2(key + 1, image + 1); diff --git a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.h b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.h index a87e885e5d8..0e178fddc39 100644 --- a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.h +++ b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.h @@ -29,7 +29,7 @@ namespace blender::compositor { */ class DistanceYCCMatteOperation : public DistanceRGBMatteOperation { protected: - float calculateDistance(float key[4], float image[4]) override; + float calculateDistance(const float key[4], const float image[4]) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc index 3804e6ec646..e0fc45811cb 100644 --- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc +++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc @@ -62,6 +62,13 @@ bool FastGaussianBlurOperation::determineDependingAreaOfInterest( return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } +void FastGaussianBlurOperation::init_data() +{ + BlurBaseOperation::init_data(); + this->m_sx = this->m_data.sizex * this->m_size / 2.0f; + this->m_sy = this->m_data.sizey * this->m_size / 2.0f; +} + void FastGaussianBlurOperation::initExecution() { BlurBaseOperation::initExecution(); @@ -117,6 +124,7 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src, unsigned int chan, unsigned int xy) { + BLI_assert(!src->is_a_single_elem()); double q, q2, sc, cf[4], tsM[9], tsu[3], tsv[3]; double *X, *Y, *W; const unsigned int src_width = src->getWidth(); @@ -257,6 +265,64 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src, #undef YVV } +void FastGaussianBlurOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + switch (input_idx) { + case IMAGE_INPUT_INDEX: + r_input_area.xmin = 0; + r_input_area.xmax = getWidth(); + r_input_area.ymin = 0; + r_input_area.ymax = getHeight(); + break; + default: + BlurBaseOperation::get_area_of_interest(input_idx, output_area, r_input_area); + return; + } +} + +void FastGaussianBlurOperation::update_memory_buffer_started(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + /* TODO(manzanilla): Add a render test and make #IIR_gauss multi-threaded with support for + * an output buffer. */ + const MemoryBuffer *input = inputs[IMAGE_INPUT_INDEX]; + MemoryBuffer *image = nullptr; + const bool is_full_output = BLI_rcti_compare(&output->get_rect(), &area); + if (is_full_output) { + image = output; + } + else { + image = new MemoryBuffer(getOutputSocket()->getDataType(), area); + } + image->copy_from(input, area); + + if ((this->m_sx == this->m_sy) && (this->m_sx > 0.0f)) { + for (const int c : IndexRange(COM_DATA_TYPE_COLOR_CHANNELS)) { + IIR_gauss(image, this->m_sx, c, 3); + } + } + else { + if (this->m_sx > 0.0f) { + for (const int c : IndexRange(COM_DATA_TYPE_COLOR_CHANNELS)) { + IIR_gauss(image, this->m_sx, c, 1); + } + } + if (this->m_sy > 0.0f) { + for (const int c : IndexRange(COM_DATA_TYPE_COLOR_CHANNELS)) { + IIR_gauss(image, this->m_sy, c, 2); + } + } + } + + if (!is_full_output) { + output->copy_from(image, area); + delete image; + } +} + FastGaussianBlurValueOperation::FastGaussianBlurValueOperation() { this->addInputSocket(DataType::Value); @@ -341,4 +407,44 @@ void *FastGaussianBlurValueOperation::initializeTileData(rcti *rect) return this->m_iirgaus; } +void FastGaussianBlurValueOperation::get_area_of_interest(const int UNUSED(input_idx), + const rcti &UNUSED(output_area), + rcti &r_input_area) +{ + r_input_area.xmin = 0; + r_input_area.xmax = getWidth(); + r_input_area.ymin = 0; + r_input_area.ymax = getHeight(); +} + +void FastGaussianBlurValueOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output), + const rcti &UNUSED(area), + Span<MemoryBuffer *> inputs) +{ + if (m_iirgaus == nullptr) { + const MemoryBuffer *image = inputs[0]; + MemoryBuffer *gauss = new MemoryBuffer(*image); + FastGaussianBlurOperation::IIR_gauss(gauss, m_sigma, 0, 3); + m_iirgaus = gauss; + } +} + +void FastGaussianBlurValueOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + MemoryBuffer *image = inputs[0]; + BuffersIterator<float> it = output->iterate_with({image, m_iirgaus}, area); + if (this->m_overlay == FAST_GAUSS_OVERLAY_MIN) { + for (; !it.is_end(); ++it) { + *it.out = MIN2(*it.in(0), *it.in(1)); + } + } + else if (this->m_overlay == FAST_GAUSS_OVERLAY_MAX) { + for (; !it.is_end(); ++it) { + *it.out = MAX2(*it.in(0), *it.in(1)); + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.h b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.h index c25afe6c4a4..f42fc76a119 100644 --- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.h +++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.h @@ -38,8 +38,19 @@ class FastGaussianBlurOperation : public BlurBaseOperation { static void IIR_gauss(MemoryBuffer *src, float sigma, unsigned int channel, unsigned int xy); void *initializeTileData(rcti *rect) override; + void init_data() override; void deinitExecution() override; void initExecution() override; + + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + void update_memory_buffer_started(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; + void update_memory_buffer_partial(MemoryBuffer *UNUSED(output), + const rcti &UNUSED(area), + Span<MemoryBuffer *> UNUSED(inputs)) override + { + } }; enum { @@ -48,7 +59,7 @@ enum { FAST_GAUSS_OVERLAY_MAX = 1, }; -class FastGaussianBlurValueOperation : public NodeOperation { +class FastGaussianBlurValueOperation : public MultiThreadedOperation { private: float m_sigma; MemoryBuffer *m_iirgaus; @@ -80,6 +91,14 @@ class FastGaussianBlurValueOperation : public NodeOperation { { this->m_overlay = overlay; } + + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + void update_memory_buffer_started(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_FlipOperation.cc b/source/blender/compositor/operations/COM_FlipOperation.cc index 8afbec4ddbe..d0dc6c0b570 100644 --- a/source/blender/compositor/operations/COM_FlipOperation.cc +++ b/source/blender/compositor/operations/COM_FlipOperation.cc @@ -75,4 +75,42 @@ bool FlipOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } +void FlipOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + BLI_assert(input_idx == 0); + UNUSED_VARS_NDEBUG(input_idx); + if (this->m_flipX) { + const int w = (int)this->getWidth() - 1; + r_input_area.xmax = (w - output_area.xmin) + 1; + r_input_area.xmin = (w - output_area.xmax) - 1; + } + else { + r_input_area.xmin = output_area.xmin; + r_input_area.xmax = output_area.xmax; + } + if (this->m_flipY) { + const int h = (int)this->getHeight() - 1; + r_input_area.ymax = (h - output_area.ymin) + 1; + r_input_area.ymin = (h - output_area.ymax) - 1; + } + else { + r_input_area.ymin = output_area.ymin; + r_input_area.ymax = output_area.ymax; + } +} + +void FlipOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input_img = inputs[0]; + for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) { + const int nx = this->m_flipX ? ((int)this->getWidth() - 1) - it.x : it.x; + const int ny = this->m_flipY ? ((int)this->getHeight() - 1) - it.y : it.y; + input_img->read_elem(nx, ny, it.out); + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_FlipOperation.h b/source/blender/compositor/operations/COM_FlipOperation.h index f26d587fde6..dba7f82c341 100644 --- a/source/blender/compositor/operations/COM_FlipOperation.h +++ b/source/blender/compositor/operations/COM_FlipOperation.h @@ -18,11 +18,11 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { -class FlipOperation : public NodeOperation { +class FlipOperation : public MultiThreadedOperation { private: SocketReader *m_inputOperation; bool m_flipX; @@ -45,6 +45,11 @@ class FlipOperation : public NodeOperation { { this->m_flipY = flipY; } + + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GammaCorrectOperation.cc b/source/blender/compositor/operations/COM_GammaCorrectOperation.cc index 16b79fddd06..1bff3b965c6 100644 --- a/source/blender/compositor/operations/COM_GammaCorrectOperation.cc +++ b/source/blender/compositor/operations/COM_GammaCorrectOperation.cc @@ -26,6 +26,7 @@ GammaCorrectOperation::GammaCorrectOperation() this->addInputSocket(DataType::Color); this->addOutputSocket(DataType::Color); this->m_inputProgram = nullptr; + flags.can_be_constant = true; } void GammaCorrectOperation::initExecution() { @@ -58,6 +59,34 @@ void GammaCorrectOperation::executePixelSampled(float output[4], } } +void GammaCorrectOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input = inputs[0]; + for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) { + float color[4]; + input->read_elem(it.x, it.y, color); + if (color[3] > 0.0f) { + color[0] /= color[3]; + color[1] /= color[3]; + color[2] /= color[3]; + } + + /* Check for negative to avoid nan's. */ + it.out[0] = color[0] > 0.0f ? color[0] * color[0] : 0.0f; + it.out[1] = color[1] > 0.0f ? color[1] * color[1] : 0.0f; + it.out[2] = color[2] > 0.0f ? color[2] * color[2] : 0.0f; + it.out[3] = color[3]; + + if (color[3] > 0.0f) { + it.out[0] *= color[3]; + it.out[1] *= color[3]; + it.out[2] *= color[3]; + } + } +} + void GammaCorrectOperation::deinitExecution() { this->m_inputProgram = nullptr; @@ -68,6 +97,7 @@ GammaUncorrectOperation::GammaUncorrectOperation() this->addInputSocket(DataType::Color); this->addOutputSocket(DataType::Color); this->m_inputProgram = nullptr; + flags.can_be_constant = true; } void GammaUncorrectOperation::initExecution() { @@ -100,6 +130,33 @@ void GammaUncorrectOperation::executePixelSampled(float output[4], } } +void GammaUncorrectOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input = inputs[0]; + for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) { + float color[4]; + input->read_elem(it.x, it.y, color); + if (color[3] > 0.0f) { + color[0] /= color[3]; + color[1] /= color[3]; + color[2] /= color[3]; + } + + it.out[0] = color[0] > 0.0f ? sqrtf(color[0]) : 0.0f; + it.out[1] = color[1] > 0.0f ? sqrtf(color[1]) : 0.0f; + it.out[2] = color[2] > 0.0f ? sqrtf(color[2]) : 0.0f; + it.out[3] = color[3]; + + if (color[3] > 0.0f) { + it.out[0] *= color[3]; + it.out[1] *= color[3]; + it.out[2] *= color[3]; + } + } +} + void GammaUncorrectOperation::deinitExecution() { this->m_inputProgram = nullptr; diff --git a/source/blender/compositor/operations/COM_GammaCorrectOperation.h b/source/blender/compositor/operations/COM_GammaCorrectOperation.h index ac3d45b94b1..2a9fde70e87 100644 --- a/source/blender/compositor/operations/COM_GammaCorrectOperation.h +++ b/source/blender/compositor/operations/COM_GammaCorrectOperation.h @@ -18,11 +18,11 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { -class GammaCorrectOperation : public NodeOperation { +class GammaCorrectOperation : public MultiThreadedOperation { private: /** * Cached reference to the inputProgram @@ -46,9 +46,13 @@ class GammaCorrectOperation : public NodeOperation { * Deinitialize the execution */ void deinitExecution() override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; -class GammaUncorrectOperation : public NodeOperation { +class GammaUncorrectOperation : public MultiThreadedOperation { private: /** * Cached reference to the inputProgram @@ -72,6 +76,10 @@ class GammaUncorrectOperation : public NodeOperation { * Deinitialize the execution */ void deinitExecution() override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.cc b/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.cc new file mode 100644 index 00000000000..9bdc652b466 --- /dev/null +++ b/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.cc @@ -0,0 +1,168 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +#include "COM_GaussianAlphaBlurBaseOperation.h" + +namespace blender::compositor { + +GaussianAlphaBlurBaseOperation::GaussianAlphaBlurBaseOperation(eDimension dim) + : BlurBaseOperation(DataType::Value) +{ + this->m_gausstab = nullptr; + this->m_filtersize = 0; + this->m_falloff = -1; /* Intentionally invalid, so we can detect uninitialized values. */ + dimension_ = dim; +} + +void GaussianAlphaBlurBaseOperation::init_data() +{ + BlurBaseOperation::init_data(); + if (execution_model_ == eExecutionModel::FullFrame) { + rad_ = max_ff(m_size * this->get_blur_size(dimension_), 0.0f); + rad_ = min_ff(rad_, MAX_GAUSSTAB_RADIUS); + m_filtersize = min_ii(ceil(rad_), MAX_GAUSSTAB_RADIUS); + } +} + +void GaussianAlphaBlurBaseOperation::initExecution() +{ + BlurBaseOperation::initExecution(); + if (execution_model_ == eExecutionModel::FullFrame) { + m_gausstab = BlurBaseOperation::make_gausstab(rad_, m_filtersize); + m_distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad_, m_filtersize, m_falloff); + } +} + +void GaussianAlphaBlurBaseOperation::deinitExecution() +{ + BlurBaseOperation::deinitExecution(); + + if (this->m_gausstab) { + MEM_freeN(this->m_gausstab); + this->m_gausstab = nullptr; + } + + if (this->m_distbuf_inv) { + MEM_freeN(this->m_distbuf_inv); + this->m_distbuf_inv = nullptr; + } +} + +void GaussianAlphaBlurBaseOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + if (input_idx != IMAGE_INPUT_INDEX) { + BlurBaseOperation::get_area_of_interest(input_idx, output_area, r_input_area); + return; + } + + r_input_area = output_area; + switch (dimension_) { + case eDimension::X: + r_input_area.xmin = output_area.xmin - m_filtersize - 1; + r_input_area.xmax = output_area.xmax + m_filtersize + 1; + break; + case eDimension::Y: + r_input_area.ymin = output_area.ymin - m_filtersize - 1; + r_input_area.ymax = output_area.ymax + m_filtersize + 1; + break; + } +} + +BLI_INLINE float finv_test(const float f, const bool test) +{ + return (LIKELY(test == false)) ? f : 1.0f - f; +} + +void GaussianAlphaBlurBaseOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + MemoryBuffer *input = inputs[IMAGE_INPUT_INDEX]; + const rcti &input_rect = input->get_rect(); + BuffersIterator<float> it = output->iterate_with({input}, area); + + int min_input_coord = -1; + int max_input_coord = -1; + int elem_stride = -1; + std::function<int()> get_current_coord; + switch (dimension_) { + case eDimension::X: + min_input_coord = input_rect.xmin; + max_input_coord = input_rect.xmax; + get_current_coord = [&] { return it.x; }; + elem_stride = input->elem_stride; + break; + case eDimension::Y: + min_input_coord = input_rect.ymin; + max_input_coord = input_rect.ymax; + get_current_coord = [&] { return it.y; }; + elem_stride = input->row_stride; + break; + } + + for (; !it.is_end(); ++it) { + const int coord = get_current_coord(); + const int coord_min = max_ii(coord - m_filtersize, min_input_coord); + const int coord_max = min_ii(coord + m_filtersize + 1, max_input_coord); + + /* *** This is the main part which is different to #GaussianBlurBaseOperation. *** */ + /* Gauss. */ + float alpha_accum = 0.0f; + float multiplier_accum = 0.0f; + + /* Dilate. */ + const bool do_invert = m_do_subtract; + /* Init with the current color to avoid unneeded lookups. */ + float value_max = finv_test(*it.in(0), do_invert); + float distfacinv_max = 1.0f; /* 0 to 1 */ + + const int step = QualityStepHelper::getStep(); + const float *in = it.in(0) + ((intptr_t)coord_min - coord) * elem_stride; + const int in_stride = elem_stride * step; + int index = (coord_min - coord) + m_filtersize; + const int index_end = index + (coord_max - coord_min); + for (; index < index_end; in += in_stride, index += step) { + float value = finv_test(*in, do_invert); + + /* Gauss. */ + float multiplier = m_gausstab[index]; + alpha_accum += value * multiplier; + multiplier_accum += multiplier; + + /* Dilate - find most extreme color. */ + if (value > value_max) { + multiplier = m_distbuf_inv[index]; + value *= multiplier; + if (value > value_max) { + value_max = value; + distfacinv_max = multiplier; + } + } + } + + /* Blend between the max value and gauss blue - gives nice feather. */ + const float value_blur = alpha_accum / multiplier_accum; + const float value_final = (value_max * distfacinv_max) + + (value_blur * (1.0f - distfacinv_max)); + *it.out = finv_test(value_final, do_invert); + } +} + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.h b/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.h new file mode 100644 index 00000000000..d7ca975ca0a --- /dev/null +++ b/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.h @@ -0,0 +1,62 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +#pragma once + +#include "COM_BlurBaseOperation.h" + +namespace blender::compositor { + +class GaussianAlphaBlurBaseOperation : public BlurBaseOperation { + protected: + float *m_gausstab; + float *m_distbuf_inv; + int m_falloff; /* Falloff for #distbuf_inv. */ + bool m_do_subtract; + int m_filtersize; + float rad_; + eDimension dimension_; + + public: + GaussianAlphaBlurBaseOperation(eDimension dim); + + virtual void init_data() override; + virtual void initExecution() override; + virtual void deinitExecution() override; + + void get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) final; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) final; + + /** + * Set subtract for Dilate/Erode functionality + */ + void setSubtract(bool subtract) + { + this->m_do_subtract = subtract; + } + void setFalloff(int falloff) + { + this->m_falloff = falloff; + } +}; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc index 7ca5dc4ca76..6710ed3cf5b 100644 --- a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc +++ b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc @@ -24,11 +24,9 @@ namespace blender::compositor { -GaussianAlphaXBlurOperation::GaussianAlphaXBlurOperation() : BlurBaseOperation(DataType::Value) +GaussianAlphaXBlurOperation::GaussianAlphaXBlurOperation() + : GaussianAlphaBlurBaseOperation(eDimension::X) { - this->m_gausstab = nullptr; - this->m_filtersize = 0; - this->m_falloff = -1; /* intentionally invalid, so we can detect uninitialized values */ } void *GaussianAlphaXBlurOperation::initializeTileData(rcti * /*rect*/) @@ -44,12 +42,11 @@ void *GaussianAlphaXBlurOperation::initializeTileData(rcti * /*rect*/) void GaussianAlphaXBlurOperation::initExecution() { - /* Until we support size input - comment this. */ - // BlurBaseOperation::initExecution(); + GaussianAlphaBlurBaseOperation::initExecution(); initMutex(); - if (this->m_sizeavailable) { + if (this->m_sizeavailable && execution_model_ == eExecutionModel::Tiled) { float rad = max_ff(m_size * m_data.sizex, 0.0f); m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); @@ -144,7 +141,7 @@ void GaussianAlphaXBlurOperation::executePixel(float output[4], int x, int y, vo void GaussianAlphaXBlurOperation::deinitExecution() { - BlurBaseOperation::deinitExecution(); + GaussianAlphaBlurBaseOperation::deinitExecution(); if (this->m_gausstab) { MEM_freeN(this->m_gausstab); diff --git a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.h b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.h index 949956fae04..2a44c639665 100644 --- a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.h +++ b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.h @@ -18,18 +18,13 @@ #pragma once -#include "COM_BlurBaseOperation.h" -#include "COM_NodeOperation.h" +#include "COM_GaussianAlphaBlurBaseOperation.h" namespace blender::compositor { -class GaussianAlphaXBlurOperation : public BlurBaseOperation { +/* TODO(manzanilla): everything to be removed with tiled implementation except the constructor. */ +class GaussianAlphaXBlurOperation : public GaussianAlphaBlurBaseOperation { private: - float *m_gausstab; - float *m_distbuf_inv; - int m_falloff; /* falloff for distbuf_inv */ - bool m_do_subtract; - int m_filtersize; void updateGauss(); public: @@ -54,18 +49,6 @@ class GaussianAlphaXBlurOperation : public BlurBaseOperation { bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; - - /** - * Set subtract for Dilate/Erode functionality - */ - void setSubtract(bool subtract) - { - this->m_do_subtract = subtract; - } - void setFalloff(int falloff) - { - this->m_falloff = falloff; - } }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc index d2385a972dd..09aeddb6573 100644 --- a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc +++ b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc @@ -24,11 +24,9 @@ namespace blender::compositor { -GaussianAlphaYBlurOperation::GaussianAlphaYBlurOperation() : BlurBaseOperation(DataType::Value) +GaussianAlphaYBlurOperation::GaussianAlphaYBlurOperation() + : GaussianAlphaBlurBaseOperation(eDimension::Y) { - this->m_gausstab = nullptr; - this->m_filtersize = 0; - this->m_falloff = -1; /* intentionally invalid, so we can detect uninitialized values */ } void *GaussianAlphaYBlurOperation::initializeTileData(rcti * /*rect*/) @@ -42,14 +40,14 @@ void *GaussianAlphaYBlurOperation::initializeTileData(rcti * /*rect*/) return buffer; } +/* TODO(manzanilla): to be removed with tiled implementation. */ void GaussianAlphaYBlurOperation::initExecution() { - /* Until we support size input - comment this. */ - // BlurBaseOperation::initExecution(); + GaussianAlphaBlurBaseOperation::initExecution(); initMutex(); - if (this->m_sizeavailable) { + if (this->m_sizeavailable && execution_model_ == eExecutionModel::Tiled) { float rad = max_ff(m_size * m_data.sizey, 0.0f); m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); @@ -58,6 +56,7 @@ void GaussianAlphaYBlurOperation::initExecution() } } +/* TODO(manzanilla): to be removed with tiled implementation. */ void GaussianAlphaYBlurOperation::updateGauss() { if (this->m_gausstab == nullptr) { @@ -143,7 +142,7 @@ void GaussianAlphaYBlurOperation::executePixel(float output[4], int x, int y, vo void GaussianAlphaYBlurOperation::deinitExecution() { - BlurBaseOperation::deinitExecution(); + GaussianAlphaBlurBaseOperation::deinitExecution(); if (this->m_gausstab) { MEM_freeN(this->m_gausstab); diff --git a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.h b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.h index d25770386c4..ef01f7e0f92 100644 --- a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.h +++ b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.h @@ -18,18 +18,13 @@ #pragma once -#include "COM_BlurBaseOperation.h" -#include "COM_NodeOperation.h" +#include "COM_GaussianAlphaBlurBaseOperation.h" namespace blender::compositor { -class GaussianAlphaYBlurOperation : public BlurBaseOperation { +/* TODO(manzanilla): everything to be removed with tiled implementation except the constructor. */ +class GaussianAlphaYBlurOperation : public GaussianAlphaBlurBaseOperation { private: - float *m_gausstab; - float *m_distbuf_inv; - bool m_do_subtract; - int m_falloff; - int m_filtersize; void updateGauss(); public: @@ -54,18 +49,6 @@ class GaussianAlphaYBlurOperation : public BlurBaseOperation { bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; - - /** - * Set subtract for Dilate/Erode functionality - */ - void setSubtract(bool subtract) - { - this->m_do_subtract = subtract; - } - void setFalloff(int falloff) - { - this->m_falloff = falloff; - } }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.cc b/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.cc new file mode 100644 index 00000000000..959f599fab4 --- /dev/null +++ b/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.cc @@ -0,0 +1,154 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +#include "COM_GaussianBlurBaseOperation.h" + +namespace blender::compositor { + +GaussianBlurBaseOperation::GaussianBlurBaseOperation(eDimension dim) + : BlurBaseOperation(DataType::Color) +{ + m_gausstab = nullptr; +#ifdef BLI_HAVE_SSE2 + m_gausstab_sse = nullptr; +#endif + m_filtersize = 0; + rad_ = 0.0f; + dimension_ = dim; +} + +void GaussianBlurBaseOperation::init_data() +{ + BlurBaseOperation::init_data(); + if (execution_model_ == eExecutionModel::FullFrame) { + rad_ = max_ff(m_size * this->get_blur_size(dimension_), 0.0f); + rad_ = min_ff(rad_, MAX_GAUSSTAB_RADIUS); + m_filtersize = min_ii(ceil(rad_), MAX_GAUSSTAB_RADIUS); + } +} + +void GaussianBlurBaseOperation::initExecution() +{ + BlurBaseOperation::initExecution(); + if (execution_model_ == eExecutionModel::FullFrame) { + m_gausstab = BlurBaseOperation::make_gausstab(rad_, m_filtersize); +#ifdef BLI_HAVE_SSE2 + m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(m_gausstab, m_filtersize); +#endif + } +} + +void GaussianBlurBaseOperation::deinitExecution() +{ + BlurBaseOperation::deinitExecution(); + + if (m_gausstab) { + MEM_freeN(m_gausstab); + m_gausstab = nullptr; + } +#ifdef BLI_HAVE_SSE2 + if (m_gausstab_sse) { + MEM_freeN(m_gausstab_sse); + m_gausstab_sse = nullptr; + } +#endif +} + +void GaussianBlurBaseOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + if (input_idx != IMAGE_INPUT_INDEX) { + BlurBaseOperation::get_area_of_interest(input_idx, output_area, r_input_area); + return; + } + + r_input_area = output_area; + switch (dimension_) { + case eDimension::X: + r_input_area.xmin = output_area.xmin - m_filtersize - 1; + r_input_area.xmax = output_area.xmax + m_filtersize + 1; + break; + case eDimension::Y: + r_input_area.ymin = output_area.ymin - m_filtersize - 1; + r_input_area.ymax = output_area.ymax + m_filtersize + 1; + break; + } +} + +void GaussianBlurBaseOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + MemoryBuffer *input = inputs[IMAGE_INPUT_INDEX]; + const rcti &input_rect = input->get_rect(); + BuffersIterator<float> it = output->iterate_with({input}, area); + + int min_input_coord = -1; + int max_input_coord = -1; + int elem_stride = -1; + std::function<int()> get_current_coord; + switch (dimension_) { + case eDimension::X: + min_input_coord = input_rect.xmin; + max_input_coord = input_rect.xmax; + elem_stride = input->elem_stride; + get_current_coord = [&] { return it.x; }; + break; + case eDimension::Y: + min_input_coord = input_rect.ymin; + max_input_coord = input_rect.ymax; + elem_stride = input->row_stride; + get_current_coord = [&] { return it.y; }; + break; + } + + for (; !it.is_end(); ++it) { + const int coord = get_current_coord(); + const int coord_min = max_ii(coord - m_filtersize, min_input_coord); + const int coord_max = min_ii(coord + m_filtersize + 1, max_input_coord); + + float ATTR_ALIGN(16) color_accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float multiplier_accum = 0.0f; + + const int step = QualityStepHelper::getStep(); + const float *in = it.in(0) + ((intptr_t)coord_min - coord) * elem_stride; + const int in_stride = elem_stride * step; + int gauss_idx = (coord_min - coord) + m_filtersize; + const int gauss_end = gauss_idx + (coord_max - coord_min); +#ifdef BLI_HAVE_SSE2 + __m128 accum_r = _mm_load_ps(color_accum); + for (; gauss_idx < gauss_end; in += in_stride, gauss_idx += step) { + __m128 reg_a = _mm_load_ps(in); + reg_a = _mm_mul_ps(reg_a, m_gausstab_sse[gauss_idx]); + accum_r = _mm_add_ps(accum_r, reg_a); + multiplier_accum += m_gausstab[gauss_idx]; + } + _mm_store_ps(color_accum, accum_r); +#else + for (; gauss_idx < gauss_end; in += in_stride, gauss_idx += step) { + const float multiplier = m_gausstab[gauss_idx]; + madd_v4_v4fl(color_accum, in, multiplier); + multiplier_accum += multiplier; + } +#endif + mul_v4_v4fl(it.out, color_accum, 1.0f / multiplier_accum); + } +} + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.h b/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.h new file mode 100644 index 00000000000..c0b27078a24 --- /dev/null +++ b/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.h @@ -0,0 +1,50 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +#pragma once + +#include "COM_BlurBaseOperation.h" + +namespace blender::compositor { + +class GaussianBlurBaseOperation : public BlurBaseOperation { + protected: + float *m_gausstab; +#ifdef BLI_HAVE_SSE2 + __m128 *m_gausstab_sse; +#endif + int m_filtersize; + float rad_; + eDimension dimension_; + + public: + GaussianBlurBaseOperation(eDimension dim); + + virtual void init_data() override; + virtual void initExecution() override; + virtual void deinitExecution() override; + + void get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) override; + virtual void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; +}; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc index b2c65ff2c96..aafc269abac 100644 --- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc +++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc @@ -40,6 +40,27 @@ void *GaussianBokehBlurOperation::initializeTileData(rcti * /*rect*/) return buffer; } +void GaussianBokehBlurOperation::init_data() +{ + BlurBaseOperation::init_data(); + const float width = this->getWidth(); + const float height = this->getHeight(); + + if (!this->m_sizeavailable) { + updateSize(); + } + + radxf_ = this->m_size * (float)this->m_data.sizex; + CLAMP(radxf_, 0.0f, width / 2.0f); + + /* Vertical. */ + radyf_ = this->m_size * (float)this->m_data.sizey; + CLAMP(radyf_, 0.0f, height / 2.0f); + + this->m_radx = ceil(radxf_); + this->m_rady = ceil(radyf_); +} + void GaussianBokehBlurOperation::initExecution() { BlurBaseOperation::initExecution(); @@ -54,39 +75,17 @@ void GaussianBokehBlurOperation::initExecution() void GaussianBokehBlurOperation::updateGauss() { if (this->m_gausstab == nullptr) { - float radxf; - float radyf; - int n; - float *dgauss; - float *ddgauss; - int j, i; - const float width = this->getWidth(); - const float height = this->getHeight(); - if (!this->m_sizeavailable) { - updateSize(); - } - radxf = this->m_size * (float)this->m_data.sizex; - CLAMP(radxf, 0.0f, width / 2.0f); - - /* vertical */ - radyf = this->m_size * (float)this->m_data.sizey; - CLAMP(radyf, 0.0f, height / 2.0f); - - this->m_radx = ceil(radxf); - this->m_rady = ceil(radyf); - int ddwidth = 2 * this->m_radx + 1; int ddheight = 2 * this->m_rady + 1; - n = ddwidth * ddheight; - + int n = ddwidth * ddheight; /* create a full filter image */ - ddgauss = (float *)MEM_mallocN(sizeof(float) * n, __func__); - dgauss = ddgauss; + float *ddgauss = (float *)MEM_mallocN(sizeof(float) * n, __func__); + float *dgauss = ddgauss; float sum = 0.0f; - float facx = (radxf > 0.0f ? 1.0f / radxf : 0.0f); - float facy = (radyf > 0.0f ? 1.0f / radyf : 0.0f); - for (j = -this->m_rady; j <= this->m_rady; j++) { - for (i = -this->m_radx; i <= this->m_radx; i++, dgauss++) { + float facx = (radxf_ > 0.0f ? 1.0f / radxf_ : 0.0f); + float facy = (radyf_ > 0.0f ? 1.0f / radyf_ : 0.0f); + for (int j = -this->m_rady; j <= this->m_rady; j++) { + for (int i = -this->m_radx; i <= this->m_radx; i++, dgauss++) { float fj = (float)j * facy; float fi = (float)i * facx; float dist = sqrt(fj * fj + fi * fi); @@ -99,7 +98,7 @@ void GaussianBokehBlurOperation::updateGauss() if (sum > 0.0f) { /* normalize */ float norm = 1.0f / sum; - for (j = n - 1; j >= 0; j--) { + for (int j = n - 1; j >= 0; j--) { ddgauss[j] *= norm; } } @@ -196,23 +195,69 @@ bool GaussianBokehBlurOperation::determineDependingAreaOfInterest( return BlurBaseOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } +void GaussianBokehBlurOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + if (input_idx != IMAGE_INPUT_INDEX) { + BlurBaseOperation::get_area_of_interest(input_idx, output_area, r_input_area); + return; + } + + r_input_area.xmax = output_area.xmax + m_radx; + r_input_area.xmin = output_area.xmin - m_radx; + r_input_area.ymax = output_area.ymax + m_rady; + r_input_area.ymin = output_area.ymin - m_rady; +} + +void GaussianBokehBlurOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input = inputs[IMAGE_INPUT_INDEX]; + BuffersIterator<float> it = output->iterate_with({}, area); + const rcti &input_rect = input->get_rect(); + for (; !it.is_end(); ++it) { + const int x = it.x; + const int y = it.y; + + const int ymin = max_ii(y - this->m_rady, input_rect.ymin); + const int ymax = min_ii(y + this->m_rady + 1, input_rect.ymax); + const int xmin = max_ii(x - this->m_radx, input_rect.xmin); + const int xmax = min_ii(x + this->m_radx + 1, input_rect.xmax); + + float tempColor[4] = {0}; + float multiplier_accum = 0; + const int step = QualityStepHelper::getStep(); + const int elem_step = step * input->elem_stride; + const int add_const = (xmin - x + this->m_radx); + const int mul_const = (this->m_radx * 2 + 1); + for (int ny = ymin; ny < ymax; ny += step) { + const float *color = input->get_elem(xmin, ny); + int gauss_index = ((ny - y) + this->m_rady) * mul_const + add_const; + const int gauss_end = gauss_index + (xmax - xmin); + for (; gauss_index < gauss_end; gauss_index += step, color += elem_step) { + const float multiplier = this->m_gausstab[gauss_index]; + madd_v4_v4fl(tempColor, color, multiplier); + multiplier_accum += multiplier; + } + } + + mul_v4_v4fl(it.out, tempColor, 1.0f / multiplier_accum); + } +} + // reference image GaussianBlurReferenceOperation::GaussianBlurReferenceOperation() : BlurBaseOperation(DataType::Color) { this->m_maintabs = nullptr; + use_variable_size_ = true; } -void *GaussianBlurReferenceOperation::initializeTileData(rcti * /*rect*/) -{ - void *buffer = getInputOperation(0)->initializeTileData(nullptr); - return buffer; -} - -void GaussianBlurReferenceOperation::initExecution() +void GaussianBlurReferenceOperation::init_data() { - BlurBaseOperation::initExecution(); - // setup gaustab + /* Setup variables for gausstab and area of interest. */ this->m_data.image_in_width = this->getWidth(); this->m_data.image_in_height = this->getHeight(); if (this->m_data.relative) { @@ -232,7 +277,7 @@ void GaussianBlurReferenceOperation::initExecution() } } - /* horizontal */ + /* Horizontal. */ m_filtersizex = (float)this->m_data.sizex; int imgx = getWidth() / 2; if (m_filtersizex > imgx) { @@ -243,7 +288,7 @@ void GaussianBlurReferenceOperation::initExecution() } m_radx = (float)m_filtersizex; - /* vertical */ + /* Vertical. */ m_filtersizey = (float)this->m_data.sizey; int imgy = getHeight() / 2; if (m_filtersizey > imgy) { @@ -253,6 +298,18 @@ void GaussianBlurReferenceOperation::initExecution() m_filtersizey = 1; } m_rady = (float)m_filtersizey; +} + +void *GaussianBlurReferenceOperation::initializeTileData(rcti * /*rect*/) +{ + void *buffer = getInputOperation(0)->initializeTileData(nullptr); + return buffer; +} + +void GaussianBlurReferenceOperation::initExecution() +{ + BlurBaseOperation::initExecution(); + updateGauss(); } @@ -363,4 +420,78 @@ bool GaussianBlurReferenceOperation::determineDependingAreaOfInterest( return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } +void GaussianBlurReferenceOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + if (input_idx != IMAGE_INPUT_INDEX) { + BlurBaseOperation::get_area_of_interest(input_idx, output_area, r_input_area); + return; + } + + const int add_x = this->m_data.sizex + 2; + const int add_y = this->m_data.sizey + 2; + r_input_area.xmax = output_area.xmax + add_x; + r_input_area.xmin = output_area.xmin - add_x; + r_input_area.ymax = output_area.ymax + add_y; + r_input_area.ymin = output_area.ymin - add_y; +} + +void GaussianBlurReferenceOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *image_input = inputs[IMAGE_INPUT_INDEX]; + MemoryBuffer *size_input = inputs[SIZE_INPUT_INDEX]; + for (BuffersIterator<float> it = output->iterate_with({size_input}, area); !it.is_end(); ++it) { + const float ref_size = *it.in(0); + int ref_radx = (int)(ref_size * m_radx); + int ref_rady = (int)(ref_size * m_rady); + if (ref_radx > m_filtersizex) { + ref_radx = m_filtersizex; + } + else if (ref_radx < 1) { + ref_radx = 1; + } + if (ref_rady > m_filtersizey) { + ref_rady = m_filtersizey; + } + else if (ref_rady < 1) { + ref_rady = 1; + } + + const int x = it.x; + const int y = it.y; + if (ref_radx == 1 && ref_rady == 1) { + image_input->read_elem(x, y, it.out); + continue; + } + + const int w = getWidth(); + const int height = getHeight(); + const int minxr = x - ref_radx < 0 ? -x : -ref_radx; + const int maxxr = x + ref_radx > w ? w - x : ref_radx; + const int minyr = y - ref_rady < 0 ? -y : -ref_rady; + const int maxyr = y + ref_rady > height ? height - y : ref_rady; + + const float *gausstabx = m_maintabs[ref_radx - 1]; + const float *gausstabcentx = gausstabx + ref_radx; + const float *gausstaby = m_maintabs[ref_rady - 1]; + const float *gausstabcenty = gausstaby + ref_rady; + + float gauss_sum = 0.0f; + float color_sum[4] = {0}; + const float *row_color = image_input->get_elem(x + minxr, y + minyr); + for (int i = minyr; i < maxyr; i++, row_color += image_input->row_stride) { + const float *color = row_color; + for (int j = minxr; j < maxxr; j++, color += image_input->elem_stride) { + const float val = gausstabcenty[i] * gausstabcentx[j]; + gauss_sum += val; + madd_v4_v4fl(color_sum, color, val); + } + } + mul_v4_v4fl(it.out, color_sum, 1.0f / gauss_sum); + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h index 59ba3d06619..a64b5b327b0 100644 --- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h +++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h @@ -28,10 +28,13 @@ class GaussianBokehBlurOperation : public BlurBaseOperation { private: float *m_gausstab; int m_radx, m_rady; + float radxf_; + float radyf_; void updateGauss(); public: GaussianBokehBlurOperation(); + void init_data() override; void initExecution() override; void *initializeTileData(rcti *rect) override; /** @@ -47,6 +50,13 @@ class GaussianBokehBlurOperation : public BlurBaseOperation { bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; + + void get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; class GaussianBlurReferenceOperation : public BlurBaseOperation { @@ -61,6 +71,7 @@ class GaussianBlurReferenceOperation : public BlurBaseOperation { public: GaussianBlurReferenceOperation(); + void init_data() override; void initExecution() override; void *initializeTileData(rcti *rect) override; /** @@ -76,6 +87,13 @@ class GaussianBlurReferenceOperation : public BlurBaseOperation { bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; + + void get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc index 4b46cfc8776..8d686265231 100644 --- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc +++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc @@ -25,13 +25,8 @@ namespace blender::compositor { -GaussianXBlurOperation::GaussianXBlurOperation() : BlurBaseOperation(DataType::Color) +GaussianXBlurOperation::GaussianXBlurOperation() : GaussianBlurBaseOperation(eDimension::X) { - this->m_gausstab = nullptr; -#ifdef BLI_HAVE_SSE2 - this->m_gausstab_sse = nullptr; -#endif - this->m_filtersize = 0; } void *GaussianXBlurOperation::initializeTileData(rcti * /*rect*/) @@ -45,13 +40,14 @@ void *GaussianXBlurOperation::initializeTileData(rcti * /*rect*/) return buffer; } +/* TODO(manzanilla): to be removed with tiled implementation. */ void GaussianXBlurOperation::initExecution() { - BlurBaseOperation::initExecution(); + GaussianBlurBaseOperation::initExecution(); initMutex(); - if (this->m_sizeavailable) { + if (this->m_sizeavailable && execution_model_ == eExecutionModel::Tiled) { float rad = max_ff(m_size * m_data.sizex, 0.0f); m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); @@ -63,6 +59,7 @@ void GaussianXBlurOperation::initExecution() } } +/* TODO(manzanilla): to be removed with tiled implementation. */ void GaussianXBlurOperation::updateGauss() { if (this->m_gausstab == nullptr) { @@ -158,7 +155,7 @@ void GaussianXBlurOperation::executeOpenCL(OpenCLDevice *device, void GaussianXBlurOperation::deinitExecution() { - BlurBaseOperation::deinitExecution(); + GaussianBlurBaseOperation::deinitExecution(); if (this->m_gausstab) { MEM_freeN(this->m_gausstab); diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h index 15277f0a42d..e09e57bad67 100644 --- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h +++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h @@ -18,18 +18,13 @@ #pragma once -#include "COM_BlurBaseOperation.h" -#include "COM_NodeOperation.h" +#include "COM_GaussianBlurBaseOperation.h" namespace blender::compositor { -class GaussianXBlurOperation : public BlurBaseOperation { +/* TODO(manzanilla): everything to be removed with tiled implementation except the constructor. */ +class GaussianXBlurOperation : public GaussianBlurBaseOperation { private: - float *m_gausstab; -#ifdef BLI_HAVE_SSE2 - __m128 *m_gausstab_sse; -#endif - int m_filtersize; void updateGauss(); public: diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc index 590ac5faa6a..32d469a0ae4 100644 --- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc +++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc @@ -25,13 +25,8 @@ namespace blender::compositor { -GaussianYBlurOperation::GaussianYBlurOperation() : BlurBaseOperation(DataType::Color) +GaussianYBlurOperation::GaussianYBlurOperation() : GaussianBlurBaseOperation(eDimension::Y) { - this->m_gausstab = nullptr; -#ifdef BLI_HAVE_SSE2 - this->m_gausstab_sse = nullptr; -#endif - this->m_filtersize = 0; } void *GaussianYBlurOperation::initializeTileData(rcti * /*rect*/) @@ -47,11 +42,11 @@ void *GaussianYBlurOperation::initializeTileData(rcti * /*rect*/) void GaussianYBlurOperation::initExecution() { - BlurBaseOperation::initExecution(); + GaussianBlurBaseOperation::initExecution(); initMutex(); - if (this->m_sizeavailable) { + if (this->m_sizeavailable && execution_model_ == eExecutionModel::Tiled) { float rad = max_ff(m_size * m_data.sizey, 0.0f); m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); @@ -158,7 +153,7 @@ void GaussianYBlurOperation::executeOpenCL(OpenCLDevice *device, void GaussianYBlurOperation::deinitExecution() { - BlurBaseOperation::deinitExecution(); + GaussianBlurBaseOperation::deinitExecution(); if (this->m_gausstab) { MEM_freeN(this->m_gausstab); diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h index 56d40849ba4..bb33f8b74cb 100644 --- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h +++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h @@ -18,18 +18,13 @@ #pragma once -#include "COM_BlurBaseOperation.h" -#include "COM_NodeOperation.h" +#include "COM_GaussianBlurBaseOperation.h" namespace blender::compositor { -class GaussianYBlurOperation : public BlurBaseOperation { +/* TODO(manzanilla): everything to be removed with tiled implementation except the constructor. */ +class GaussianYBlurOperation : public GaussianBlurBaseOperation { private: - float *m_gausstab; -#ifdef BLI_HAVE_SSE2 - __m128 *m_gausstab_sse; -#endif - int m_filtersize; void updateGauss(); public: diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.cc b/source/blender/compositor/operations/COM_KeyingBlurOperation.cc index 994b00cd3f4..d5ebd5e9df7 100644 --- a/source/blender/compositor/operations/COM_KeyingBlurOperation.cc +++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.cc @@ -96,4 +96,67 @@ bool KeyingBlurOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } +void KeyingBlurOperation::get_area_of_interest(const int UNUSED(input_idx), + const rcti &output_area, + rcti &r_input_area) +{ + switch (m_axis) { + case BLUR_AXIS_X: + r_input_area.xmin = output_area.xmin - m_size; + r_input_area.ymin = output_area.ymin; + r_input_area.xmax = output_area.xmax + m_size; + r_input_area.ymax = output_area.ymax; + break; + case BLUR_AXIS_Y: + r_input_area.xmin = output_area.xmin; + r_input_area.ymin = output_area.ymin - m_size; + r_input_area.xmax = output_area.xmax; + r_input_area.ymax = output_area.ymax + m_size; + break; + default: + BLI_assert_msg(0, "Unknown axis"); + break; + } +} + +void KeyingBlurOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input = inputs[0]; + BuffersIterator<float> it = output->iterate_with(inputs, area); + + int coord_max; + int elem_stride; + std::function<int()> get_current_coord; + switch (m_axis) { + case BLUR_AXIS_X: + get_current_coord = [&] { return it.x; }; + coord_max = this->getWidth(); + elem_stride = input->elem_stride; + break; + case BLUR_AXIS_Y: + get_current_coord = [&] { return it.y; }; + coord_max = this->getHeight(); + elem_stride = input->row_stride; + break; + } + + for (; !it.is_end(); ++it) { + const int coord = get_current_coord(); + const int start_coord = MAX2(0, coord - m_size + 1); + const int end_coord = MIN2(coord_max, coord + m_size); + const int count = end_coord - start_coord; + + float sum = 0.0f; + const float *start = it.in(0) + (start_coord - coord) * elem_stride; + const float *end = start + count * elem_stride; + for (const float *elem = start; elem < end; elem += elem_stride) { + sum += *elem; + } + + *it.out = sum / count; + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.h b/source/blender/compositor/operations/COM_KeyingBlurOperation.h index b055d7713f1..b290b905e63 100644 --- a/source/blender/compositor/operations/COM_KeyingBlurOperation.h +++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.h @@ -18,14 +18,14 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { /** * Class with implementation of blurring for keying node */ -class KeyingBlurOperation : public NodeOperation { +class KeyingBlurOperation : public MultiThreadedOperation { protected: int m_size; int m_axis; @@ -54,6 +54,13 @@ class KeyingBlurOperation : public NodeOperation { bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; + + void get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.cc b/source/blender/compositor/operations/COM_KeyingClipOperation.cc index 4029be4e077..817c920ed91 100644 --- a/source/blender/compositor/operations/COM_KeyingClipOperation.cc +++ b/source/blender/compositor/operations/COM_KeyingClipOperation.cc @@ -130,4 +130,89 @@ bool KeyingClipOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } +void KeyingClipOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + BLI_assert(input_idx == 0); + UNUSED_VARS_NDEBUG(input_idx); + r_input_area.xmin = output_area.xmin - m_kernelRadius; + r_input_area.xmax = output_area.xmax + m_kernelRadius; + r_input_area.ymin = output_area.ymin - m_kernelRadius; + r_input_area.ymax = output_area.ymax + m_kernelRadius; +} + +void KeyingClipOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input = inputs[0]; + BuffersIterator<float> it = output->iterate_with(inputs, area); + + const int delta = m_kernelRadius; + const float tolerance = m_kernelTolerance; + const int width = this->getWidth(); + const int height = this->getHeight(); + const int row_stride = input->row_stride; + const int elem_stride = input->elem_stride; + for (; !it.is_end(); ++it) { + const int x = it.x; + const int y = it.y; + + const int start_x = MAX2(0, x - delta + 1); + const int start_y = MAX2(0, y - delta + 1); + const int end_x = MIN2(x + delta, width); + const int end_y = MIN2(y + delta, height); + const int x_len = end_x - start_x; + const int y_len = end_y - start_y; + + const int total_count = x_len * y_len - 1; + const int threshold_count = ceil((float)total_count * 0.9f); + bool ok = false; + if (delta == 0) { + ok = true; + } + + const float *main_elem = it.in(0); + const float value = *main_elem; + const float *row = input->get_elem(start_x, start_y); + const float *end_row = row + y_len * row_stride; + int count = 0; + for (; ok == false && row < end_row; row += row_stride) { + const float *end_elem = row + x_len * elem_stride; + for (const float *elem = row; ok == false && elem < end_elem; elem += elem_stride) { + if (UNLIKELY(elem == main_elem)) { + continue; + } + + const float current_value = *elem; + if (fabsf(current_value - value) < tolerance) { + count++; + if (count >= threshold_count) { + ok = true; + } + } + } + } + + if (m_isEdgeMatte) { + *it.out = ok ? 0.0f : 1.0f; + } + else { + if (!ok) { + *it.out = value; + } + else if (value < m_clipBlack) { + *it.out = 0.0f; + } + else if (value >= m_clipWhite) { + *it.out = 1.0f; + } + else { + *it.out = (value - m_clipBlack) / (m_clipWhite - m_clipBlack); + } + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.h b/source/blender/compositor/operations/COM_KeyingClipOperation.h index 0a21fb48c99..1a17d591781 100644 --- a/source/blender/compositor/operations/COM_KeyingClipOperation.h +++ b/source/blender/compositor/operations/COM_KeyingClipOperation.h @@ -18,14 +18,14 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { /** * Class with implementation of black/white clipping for keying node */ -class KeyingClipOperation : public NodeOperation { +class KeyingClipOperation : public MultiThreadedOperation { protected: float m_clipBlack; float m_clipWhite; @@ -68,6 +68,13 @@ class KeyingClipOperation : public NodeOperation { bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; + + void get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingDespillOperation.cc b/source/blender/compositor/operations/COM_KeyingDespillOperation.cc index d31a88cb91e..620b767e584 100644 --- a/source/blender/compositor/operations/COM_KeyingDespillOperation.cc +++ b/source/blender/compositor/operations/COM_KeyingDespillOperation.cc @@ -36,6 +36,7 @@ KeyingDespillOperation::KeyingDespillOperation() this->m_pixelReader = nullptr; this->m_screenReader = nullptr; + flags.can_be_constant = true; } void KeyingDespillOperation::initExecution() @@ -82,4 +83,32 @@ void KeyingDespillOperation::executePixelSampled(float output[4], } } +void KeyingDespillOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + const float *pixel_color = it.in(0); + const float *screen_color = it.in(1); + + const int screen_primary_channel = max_axis_v3(screen_color); + const int other_1 = (screen_primary_channel + 1) % 3; + const int other_2 = (screen_primary_channel + 2) % 3; + + const int min_channel = MIN2(other_1, other_2); + const int max_channel = MAX2(other_1, other_2); + + const float average_value = m_colorBalance * pixel_color[min_channel] + + (1.0f - m_colorBalance) * pixel_color[max_channel]; + const float amount = (pixel_color[screen_primary_channel] - average_value); + + copy_v4_v4(it.out, pixel_color); + + const float amount_despill = m_despillFactor * amount; + if (amount_despill > 0.0f) { + it.out[screen_primary_channel] = pixel_color[screen_primary_channel] - amount_despill; + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingDespillOperation.h b/source/blender/compositor/operations/COM_KeyingDespillOperation.h index 279ac60e6e9..16bed651d3a 100644 --- a/source/blender/compositor/operations/COM_KeyingDespillOperation.h +++ b/source/blender/compositor/operations/COM_KeyingDespillOperation.h @@ -18,14 +18,14 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { /** * Class with implementation of keying despill node */ -class KeyingDespillOperation : public NodeOperation { +class KeyingDespillOperation : public MultiThreadedOperation { protected: SocketReader *m_pixelReader; SocketReader *m_screenReader; @@ -48,6 +48,10 @@ class KeyingDespillOperation : public NodeOperation { } void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingOperation.cc b/source/blender/compositor/operations/COM_KeyingOperation.cc index e786e4b8219..3edb5a5d34e 100644 --- a/source/blender/compositor/operations/COM_KeyingOperation.cc +++ b/source/blender/compositor/operations/COM_KeyingOperation.cc @@ -110,4 +110,49 @@ void KeyingOperation::executePixelSampled(float output[4], float x, float y, Pix } } +void KeyingOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + const float *pixel_color = it.in(0); + const float *screen_color = it.in(1); + + const int primary_channel = max_axis_v3(screen_color); + const float min_pixel_color = min_fff(pixel_color[0], pixel_color[1], pixel_color[2]); + + if (min_pixel_color > 1.0f) { + /* Overexposure doesn't happen on screen itself and usually happens + * on light sources in the shot, this need to be checked separately + * because saturation and falloff calculation is based on the fact + * that pixels are not overexposed. + */ + it.out[0] = 1.0f; + } + else { + const float saturation = get_pixel_saturation(pixel_color, m_screenBalance, primary_channel); + const float screen_saturation = get_pixel_saturation( + screen_color, m_screenBalance, primary_channel); + + if (saturation < 0) { + /* Means main channel of pixel is different from screen, + * assume this is completely a foreground. + */ + it.out[0] = 1.0f; + } + else if (saturation >= screen_saturation) { + /* Matched main channels and higher saturation on pixel + * is treated as completely background. + */ + it.out[0] = 0.0f; + } + else { + /* Nice alpha falloff on edges. */ + const float distance = 1.0f - saturation / screen_saturation; + it.out[0] = distance; + } + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingOperation.h b/source/blender/compositor/operations/COM_KeyingOperation.h index 3d41ecaa0f6..e134ad54896 100644 --- a/source/blender/compositor/operations/COM_KeyingOperation.h +++ b/source/blender/compositor/operations/COM_KeyingOperation.h @@ -20,7 +20,7 @@ #include <string.h> -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" #include "BLI_listbase.h" @@ -29,7 +29,7 @@ namespace blender::compositor { /** * Class with implementation of keying node */ -class KeyingOperation : public NodeOperation { +class KeyingOperation : public MultiThreadedOperation { protected: SocketReader *m_pixelReader; SocketReader *m_screenReader; @@ -48,6 +48,10 @@ class KeyingOperation : public NodeOperation { } void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.cc b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc index 17b613246ad..c00aafc19a2 100644 --- a/source/blender/compositor/operations/COM_KeyingScreenOperation.cc +++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc @@ -39,12 +39,21 @@ KeyingScreenOperation::KeyingScreenOperation() this->m_framenumber = 0; this->m_trackingObject[0] = 0; flags.complex = true; + m_cachedTriangulation = nullptr; } void KeyingScreenOperation::initExecution() { initMutex(); - this->m_cachedTriangulation = nullptr; + if (execution_model_ == eExecutionModel::FullFrame) { + BLI_assert(m_cachedTriangulation == nullptr); + if (m_movieClip) { + m_cachedTriangulation = buildVoronoiTriangulation(); + } + } + else { + this->m_cachedTriangulation = nullptr; + } } void KeyingScreenOperation::deinitExecution() @@ -226,7 +235,7 @@ KeyingScreenOperation::TriangulationData *KeyingScreenOperation::buildVoronoiTri return triangulation; } -void *KeyingScreenOperation::initializeTileData(rcti *rect) +KeyingScreenOperation::TileData *KeyingScreenOperation::triangulate(const rcti *rect) { TileData *tile_data; TriangulationData *triangulation; @@ -234,18 +243,6 @@ void *KeyingScreenOperation::initializeTileData(rcti *rect) int chunk_size = 20; int i; - if (this->m_movieClip == nullptr) { - return nullptr; - } - - if (!this->m_cachedTriangulation) { - lockMutex(); - if (this->m_cachedTriangulation == nullptr) { - this->m_cachedTriangulation = buildVoronoiTriangulation(); - } - unlockMutex(); - } - triangulation = this->m_cachedTriangulation; if (!triangulation) { @@ -278,6 +275,23 @@ void *KeyingScreenOperation::initializeTileData(rcti *rect) return tile_data; } +void *KeyingScreenOperation::initializeTileData(rcti *rect) +{ + if (this->m_movieClip == nullptr) { + return nullptr; + } + + if (!this->m_cachedTriangulation) { + lockMutex(); + if (this->m_cachedTriangulation == nullptr) { + this->m_cachedTriangulation = buildVoronoiTriangulation(); + } + unlockMutex(); + } + + return triangulate(rect); +} + void KeyingScreenOperation::deinitializeTileData(rcti * /*rect*/, void *data) { TileData *tile_data = (TileData *)data; @@ -347,4 +361,57 @@ void KeyingScreenOperation::executePixel(float output[4], int x, int y, void *da } } +void KeyingScreenOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + if (m_movieClip == nullptr) { + output->fill(area, COM_COLOR_BLACK); + return; + } + + TileData *tri_area = this->triangulate(&area); + BLI_assert(tri_area != nullptr); + + const int *triangles = tri_area->triangles; + const int num_triangles = tri_area->triangles_total; + const TriangulationData *triangulation = m_cachedTriangulation; + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + copy_v4_v4(it.out, COM_COLOR_BLACK); + + const float co[2] = {(float)it.x, (float)it.y}; + for (int i = 0; i < num_triangles; i++) { + const int triangle_idx = triangles[i]; + const rcti *rect = &triangulation->triangles_AABB[triangle_idx]; + + if (!BLI_rcti_isect_pt(rect, it.x, it.y)) { + continue; + } + + const int *triangle = triangulation->triangles[triangle_idx]; + const VoronoiTriangulationPoint &a = triangulation->triangulated_points[triangle[0]]; + const VoronoiTriangulationPoint &b = triangulation->triangulated_points[triangle[1]]; + const VoronoiTriangulationPoint &c = triangulation->triangulated_points[triangle[2]]; + + float w[3]; + if (!barycentric_coords_v2(a.co, b.co, c.co, co, w)) { + continue; + } + + if (barycentric_inside_triangle_v2(w)) { + it.out[0] = a.color[0] * w[0] + b.color[0] * w[1] + c.color[0] * w[2]; + it.out[1] = a.color[1] * w[0] + b.color[1] * w[1] + c.color[1] * w[2]; + it.out[2] = a.color[2] * w[0] + b.color[2] * w[1] + c.color[2] * w[2]; + break; + } + } + } + + if (tri_area->triangles) { + MEM_freeN(tri_area->triangles); + } + + MEM_freeN(tri_area); +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.h b/source/blender/compositor/operations/COM_KeyingScreenOperation.h index 4118d229be9..0bc47dbea30 100644 --- a/source/blender/compositor/operations/COM_KeyingScreenOperation.h +++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.h @@ -20,7 +20,7 @@ #include <string.h> -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" #include "DNA_movieclip_types.h" @@ -34,7 +34,7 @@ namespace blender::compositor { /** * Class with implementation of green screen gradient rasterization */ -class KeyingScreenOperation : public NodeOperation { +class KeyingScreenOperation : public MultiThreadedOperation { protected: typedef struct TriangulationData { VoronoiTriangulationPoint *triangulated_points; @@ -43,6 +43,7 @@ class KeyingScreenOperation : public NodeOperation { rcti *triangles_AABB; } TriangulationData; + /* TODO(manzanilla): rename to #TrianguledArea on removing tiled implementation. */ typedef struct TileData { int *triangles; int triangles_total; @@ -84,6 +85,13 @@ class KeyingScreenOperation : public NodeOperation { } void executePixel(float output[4], int x, int y, void *data) override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; + + private: + TileData *triangulate(const rcti *rect); }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc index 5ca16e40ce3..c642c60b912 100644 --- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc +++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc @@ -29,6 +29,7 @@ LuminanceMatteOperation::LuminanceMatteOperation() addOutputSocket(DataType::Value); this->m_inputImageProgram = nullptr; + flags.can_be_constant = true; } void LuminanceMatteOperation::initExecution() @@ -78,4 +79,39 @@ void LuminanceMatteOperation::executePixelSampled(float output[4], output[0] = min_ff(alpha, inColor[3]); } +void LuminanceMatteOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + const float *color = it.in(0); + const float luminance = IMB_colormanagement_get_luminance(color); + + /* One line thread-friend algorithm: + * `it.out[0] = MIN2(color[3], MIN2(1.0f, MAX2(0.0f, ((luminance - low) / (high - low))));` + */ + + /* Test range. */ + const float high = m_settings->t1; + const float low = m_settings->t2; + float alpha; + if (luminance > high) { + alpha = 1.0f; + } + else if (luminance < low) { + alpha = 0.0f; + } + else { /* Blend. */ + alpha = (luminance - low) / (high - low); + } + + /* Store matte(alpha) value in [0] to go with + * COM_SetAlphaMultiplyOperation and the Value output. + */ + + /* Don't make something that was more transparent less transparent. */ + it.out[0] = MIN2(alpha, color[3]); + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.h b/source/blender/compositor/operations/COM_LuminanceMatteOperation.h index 035c68b9d59..aedfc715382 100644 --- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.h +++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.h @@ -18,7 +18,7 @@ #pragma once -#include "COM_MixOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { @@ -26,7 +26,7 @@ namespace blender::compositor { * this program converts an input color to an output value. * it assumes we are in sRGB color space. */ -class LuminanceMatteOperation : public NodeOperation { +class LuminanceMatteOperation : public MultiThreadedOperation { private: NodeChroma *m_settings; SocketReader *m_inputImageProgram; @@ -49,6 +49,10 @@ class LuminanceMatteOperation : public NodeOperation { { this->m_settings = nodeChroma; } + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cc b/source/blender/compositor/operations/COM_MapUVOperation.cc index 74e3d965d41..ad047c619f8 100644 --- a/source/blender/compositor/operations/COM_MapUVOperation.cc +++ b/source/blender/compositor/operations/COM_MapUVOperation.cc @@ -34,10 +34,26 @@ MapUVOperation::MapUVOperation() this->m_inputColorProgram = nullptr; } +void MapUVOperation::init_data() +{ + NodeOperation *image_input = get_input_operation(0); + image_width_ = image_input->getWidth(); + image_height_ = image_input->getHeight(); + + NodeOperation *uv_input = get_input_operation(1); + uv_width_ = uv_input->getWidth(); + uv_height_ = uv_input->getHeight(); +} + void MapUVOperation::initExecution() { this->m_inputColorProgram = this->getInputSocketReader(0); this->m_inputUVProgram = this->getInputSocketReader(1); + if (execution_model_ == eExecutionModel::Tiled) { + uv_input_read_fn_ = [=](float x, float y, float *out) { + this->m_inputUVProgram->readSampled(out, x, y, PixelSampler::Bilinear); + }; + } } void MapUVOperation::executePixelSampled(float output[4], @@ -81,9 +97,7 @@ void MapUVOperation::executePixelSampled(float output[4], bool MapUVOperation::read_uv(float x, float y, float &r_u, float &r_v, float &r_alpha) { - float width = m_inputUVProgram->getWidth(); - float height = m_inputUVProgram->getHeight(); - if (x < 0.0f || x >= width || y < 0.0f || y >= height) { + if (x < 0.0f || x >= uv_width_ || y < 0.0f || y >= uv_height_) { r_u = 0.0f; r_v = 0.0f; r_alpha = 0.0f; @@ -91,9 +105,9 @@ bool MapUVOperation::read_uv(float x, float y, float &r_u, float &r_v, float &r_ } float vector[3]; - m_inputUVProgram->readSampled(vector, x, y, PixelSampler::Bilinear); - r_u = vector[0] * m_inputColorProgram->getWidth(); - r_v = vector[1] * m_inputColorProgram->getHeight(); + uv_input_read_fn_(x, y, vector); + r_u = vector[0] * image_width_; + r_v = vector[1] * image_height_; r_alpha = vector[2]; return true; } @@ -186,4 +200,75 @@ bool MapUVOperation::determineDependingAreaOfInterest(rcti *input, return false; } +void MapUVOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + switch (input_idx) { + case 0: { + r_input_area.xmin = 0; + r_input_area.xmax = image_width_; + r_input_area.ymin = 0; + r_input_area.ymax = image_height_; + break; + } + case 1: { + r_input_area = output_area; + expand_area_for_sampler(r_input_area, PixelSampler::Bilinear); + break; + } + } +} + +void MapUVOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output), + const rcti &UNUSED(area), + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *uv_input = inputs[1]; + uv_input_read_fn_ = [=](float x, float y, float *out) { + uv_input->read_elem_bilinear(x, y, out); + }; +} + +void MapUVOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input_image = inputs[0]; + for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) { + float xy[2] = {(float)it.x, (float)it.y}; + float uv[2]; + float deriv[2][2]; + float alpha; + pixelTransform(xy, uv, deriv, alpha); + if (alpha == 0.0f) { + zero_v4(it.out); + continue; + } + + /* EWA filtering. */ + input_image->read_elem_filtered(uv[0], uv[1], deriv[0], deriv[1], it.out); + + /* UV to alpha threshold. */ + const float threshold = this->m_alpha * 0.05f; + /* XXX alpha threshold is used to fade out pixels on boundaries with invalid derivatives. + * this calculation is not very well defined, should be looked into if it becomes a problem ... + */ + const float du = len_v2(deriv[0]); + const float dv = len_v2(deriv[1]); + const float factor = 1.0f - threshold * (du / image_width_ + dv / image_height_); + if (factor < 0.0f) { + alpha = 0.0f; + } + else { + alpha *= factor; + } + + /* "premul" */ + if (alpha < 1.0f) { + mul_v4_fl(it.out, alpha); + } + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MapUVOperation.h b/source/blender/compositor/operations/COM_MapUVOperation.h index eb5f7d49122..65fbcb461c9 100644 --- a/source/blender/compositor/operations/COM_MapUVOperation.h +++ b/source/blender/compositor/operations/COM_MapUVOperation.h @@ -18,11 +18,11 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { -class MapUVOperation : public NodeOperation { +class MapUVOperation : public MultiThreadedOperation { private: /** * Cached reference to the inputProgram @@ -30,8 +30,15 @@ class MapUVOperation : public NodeOperation { SocketReader *m_inputUVProgram; SocketReader *m_inputColorProgram; + int uv_width_; + int uv_height_; + int image_width_; + int image_height_; + float m_alpha; + std::function<void(float x, float y, float *out)> uv_input_read_fn_; + public: MapUVOperation(); @@ -49,6 +56,8 @@ class MapUVOperation : public NodeOperation { void pixelTransform(const float xy[2], float r_uv[2], float r_deriv[2][2], float &r_alpha); + void init_data() override; + /** * Initialize the execution */ @@ -64,6 +73,14 @@ class MapUVOperation : public NodeOperation { this->m_alpha = alpha; } + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + void update_memory_buffer_started(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; + private: bool read_uv(float x, float y, float &r_u, float &r_v, float &r_alpha); }; diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cc b/source/blender/compositor/operations/COM_MathBaseOperation.cc index a94c14347fb..2256dce011b 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.cc +++ b/source/blender/compositor/operations/COM_MathBaseOperation.cc @@ -24,6 +24,8 @@ namespace blender::compositor { MathBaseOperation::MathBaseOperation() { + /* TODO(manzanilla): after removing tiled implementation, template this class to only add needed + * number of inputs. */ this->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value); @@ -32,6 +34,7 @@ MathBaseOperation::MathBaseOperation() this->m_inputValue2Operation = nullptr; this->m_inputValue3Operation = nullptr; this->m_useClamp = false; + this->flags.can_be_constant = true; } void MathBaseOperation::initExecution() @@ -73,6 +76,14 @@ void MathBaseOperation::clampIfNeeded(float *color) } } +void MathBaseOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + BuffersIterator<float> it = output->iterate_with(inputs, area); + update_memory_buffer_partial(it); +} + void MathAddOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) { float inputValue1[4]; @@ -139,6 +150,14 @@ void MathDivideOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathDivideOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + const float divisor = *it.in(1); + *it.out = clamp_when_enabled((divisor == 0) ? 0 : *it.in(0) / divisor); + } +} + void MathSineOperation::executePixelSampled(float output[4], float x, float y, @@ -155,6 +174,14 @@ void MathSineOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathSineOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = sin(*it.in(0)); + clamp_when_enabled(it.out); + } +} + void MathCosineOperation::executePixelSampled(float output[4], float x, float y, @@ -171,6 +198,14 @@ void MathCosineOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathCosineOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = cos(*it.in(0)); + clamp_when_enabled(it.out); + } +} + void MathTangentOperation::executePixelSampled(float output[4], float x, float y, @@ -187,6 +222,14 @@ void MathTangentOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathTangentOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = tan(*it.in(0)); + clamp_when_enabled(it.out); + } +} + void MathHyperbolicSineOperation::executePixelSampled(float output[4], float x, float y, @@ -203,6 +246,14 @@ void MathHyperbolicSineOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathHyperbolicSineOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = sinh(*it.in(0)); + clamp_when_enabled(it.out); + } +} + void MathHyperbolicCosineOperation::executePixelSampled(float output[4], float x, float y, @@ -219,6 +270,14 @@ void MathHyperbolicCosineOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathHyperbolicCosineOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = cosh(*it.in(0)); + clamp_when_enabled(it.out); + } +} + void MathHyperbolicTangentOperation::executePixelSampled(float output[4], float x, float y, @@ -235,6 +294,14 @@ void MathHyperbolicTangentOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathHyperbolicTangentOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = tanh(*it.in(0)); + clamp_when_enabled(it.out); + } +} + void MathArcSineOperation::executePixelSampled(float output[4], float x, float y, @@ -256,6 +323,14 @@ void MathArcSineOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathArcSineOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + float value1 = *it.in(0); + *it.out = clamp_when_enabled((value1 <= 1 && value1 >= -1) ? asin(value1) : 0.0f); + } +} + void MathArcCosineOperation::executePixelSampled(float output[4], float x, float y, @@ -277,6 +352,14 @@ void MathArcCosineOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathArcCosineOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + float value1 = *it.in(0); + *it.out = clamp_when_enabled((value1 <= 1 && value1 >= -1) ? acos(value1) : 0.0f); + } +} + void MathArcTangentOperation::executePixelSampled(float output[4], float x, float y, @@ -293,6 +376,14 @@ void MathArcTangentOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathArcTangentOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = atan(*it.in(0)); + clamp_when_enabled(it.out); + } +} + void MathPowerOperation::executePixelSampled(float output[4], float x, float y, @@ -321,6 +412,29 @@ void MathPowerOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathPowerOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + const float value1 = *it.in(0); + const float value2 = *it.in(1); + if (value1 >= 0) { + *it.out = pow(value1, value2); + } + else { + const float y_mod_1 = fmod(value2, 1); + /* If input value is not nearly an integer, fall back to zero, nicer than straight rounding. + */ + if (y_mod_1 > 0.999f || y_mod_1 < 0.001f) { + *it.out = pow(value1, floorf(value2 + 0.5f)); + } + else { + *it.out = 0.0f; + } + } + clamp_when_enabled(it.out); + } +} + void MathLogarithmOperation::executePixelSampled(float output[4], float x, float y, @@ -342,6 +456,21 @@ void MathLogarithmOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathLogarithmOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + const float value1 = *it.in(0); + const float value2 = *it.in(1); + if (value1 > 0 && value2 > 0) { + *it.out = log(value1) / log(value2); + } + else { + *it.out = 0.0; + } + clamp_when_enabled(it.out); + } +} + void MathMinimumOperation::executePixelSampled(float output[4], float x, float y, @@ -358,6 +487,14 @@ void MathMinimumOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathMinimumOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = MIN2(*it.in(0), *it.in(1)); + clamp_when_enabled(it.out); + } +} + void MathMaximumOperation::executePixelSampled(float output[4], float x, float y, @@ -374,6 +511,14 @@ void MathMaximumOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathMaximumOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = MAX2(*it.in(0), *it.in(1)); + clamp_when_enabled(it.out); + } +} + void MathRoundOperation::executePixelSampled(float output[4], float x, float y, @@ -390,6 +535,14 @@ void MathRoundOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathRoundOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = round(*it.in(0)); + clamp_when_enabled(it.out); + } +} + void MathLessThanOperation::executePixelSampled(float output[4], float x, float y, @@ -443,6 +596,15 @@ void MathModuloOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathModuloOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + const float value2 = *it.in(1); + *it.out = (value2 == 0) ? 0 : fmod(*it.in(0), value2); + clamp_when_enabled(it.out); + } +} + void MathAbsoluteOperation::executePixelSampled(float output[4], float x, float y, @@ -457,6 +619,14 @@ void MathAbsoluteOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathAbsoluteOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = fabs(*it.in(0)); + clamp_when_enabled(it.out); + } +} + void MathRadiansOperation::executePixelSampled(float output[4], float x, float y, @@ -471,6 +641,14 @@ void MathRadiansOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathRadiansOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = DEG2RADF(*it.in(0)); + clamp_when_enabled(it.out); + } +} + void MathDegreesOperation::executePixelSampled(float output[4], float x, float y, @@ -485,6 +663,14 @@ void MathDegreesOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathDegreesOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = RAD2DEGF(*it.in(0)); + clamp_when_enabled(it.out); + } +} + void MathArcTan2Operation::executePixelSampled(float output[4], float x, float y, @@ -501,6 +687,14 @@ void MathArcTan2Operation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathArcTan2Operation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = atan2(*it.in(0), *it.in(1)); + clamp_when_enabled(it.out); + } +} + void MathFloorOperation::executePixelSampled(float output[4], float x, float y, @@ -515,6 +709,14 @@ void MathFloorOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathFloorOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = floor(*it.in(0)); + clamp_when_enabled(it.out); + } +} + void MathCeilOperation::executePixelSampled(float output[4], float x, float y, @@ -529,6 +731,14 @@ void MathCeilOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathCeilOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = ceil(*it.in(0)); + clamp_when_enabled(it.out); + } +} + void MathFractOperation::executePixelSampled(float output[4], float x, float y, @@ -543,6 +753,14 @@ void MathFractOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathFractOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + const float value = *it.in(0); + *it.out = clamp_when_enabled(value - floor(value)); + } +} + void MathSqrtOperation::executePixelSampled(float output[4], float x, float y, @@ -562,6 +780,14 @@ void MathSqrtOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathSqrtOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + const float value = *it.in(0); + *it.out = clamp_when_enabled(value > 0 ? sqrt(value) : 0.0f); + } +} + void MathInverseSqrtOperation::executePixelSampled(float output[4], float x, float y, @@ -581,6 +807,14 @@ void MathInverseSqrtOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathInverseSqrtOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + const float value = *it.in(0); + *it.out = clamp_when_enabled(value > 0 ? 1.0f / sqrt(value) : 0.0f); + } +} + void MathSignOperation::executePixelSampled(float output[4], float x, float y, @@ -595,6 +829,14 @@ void MathSignOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathSignOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = compatible_signf(*it.in(0)); + clamp_when_enabled(it.out); + } +} + void MathExponentOperation::executePixelSampled(float output[4], float x, float y, @@ -609,6 +851,14 @@ void MathExponentOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathExponentOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = expf(*it.in(0)); + clamp_when_enabled(it.out); + } +} + void MathTruncOperation::executePixelSampled(float output[4], float x, float y, @@ -623,6 +873,15 @@ void MathTruncOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathTruncOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + const float value = *it.in(0); + *it.out = (value >= 0.0f) ? floor(value) : ceil(value); + clamp_when_enabled(it.out); + } +} + void MathSnapOperation::executePixelSampled(float output[4], float x, float y, @@ -644,6 +903,21 @@ void MathSnapOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathSnapOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + const float value1 = *it.in(0); + const float value2 = *it.in(1); + if (value1 == 0 || value2 == 0) { /* Avoid dividing by zero. */ + *it.out = 0.0f; + } + else { + *it.out = floorf(value1 / value2) * value2; + } + clamp_when_enabled(it.out); + } +} + void MathWrapOperation::executePixelSampled(float output[4], float x, float y, @@ -662,6 +936,14 @@ void MathWrapOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathWrapOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = wrapf(*it.in(0), *it.in(1), *it.in(2)); + clamp_when_enabled(it.out); + } +} + void MathPingpongOperation::executePixelSampled(float output[4], float x, float y, @@ -678,6 +960,14 @@ void MathPingpongOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathPingpongOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = pingpongf(*it.in(0), *it.in(1)); + clamp_when_enabled(it.out); + } +} + void MathCompareOperation::executePixelSampled(float output[4], float x, float y, @@ -697,6 +987,14 @@ void MathCompareOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathCompareOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = (fabsf(*it.in(0) - *it.in(1)) <= MAX2(*it.in(2), 1e-5f)) ? 1.0f : 0.0f; + clamp_when_enabled(it.out); + } +} + void MathMultiplyAddOperation::executePixelSampled(float output[4], float x, float y, @@ -715,6 +1013,14 @@ void MathMultiplyAddOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathMultiplyAddOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = it.in(0)[0] * it.in(1)[0] + it.in(2)[0]; + clamp_when_enabled(it.out); + } +} + void MathSmoothMinOperation::executePixelSampled(float output[4], float x, float y, @@ -733,6 +1039,14 @@ void MathSmoothMinOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathSmoothMinOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = smoothminf(*it.in(0), *it.in(1), *it.in(2)); + clamp_when_enabled(it.out); + } +} + void MathSmoothMaxOperation::executePixelSampled(float output[4], float x, float y, @@ -751,4 +1065,12 @@ void MathSmoothMaxOperation::executePixelSampled(float output[4], clampIfNeeded(output); } +void MathSmoothMaxOperation::update_memory_buffer_partial(BuffersIterator<float> &it) +{ + for (; !it.is_end(); ++it) { + *it.out = -smoothminf(-it.in(0)[0], -it.in(1)[0], it.in(2)[0]); + clamp_when_enabled(it.out); + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.h b/source/blender/compositor/operations/COM_MathBaseOperation.h index 08794c8db22..d2da05db68e 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.h +++ b/source/blender/compositor/operations/COM_MathBaseOperation.h @@ -18,7 +18,7 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { @@ -26,7 +26,7 @@ namespace blender::compositor { * this program converts an input color to an output value. * it assumes we are in sRGB color space. */ -class MathBaseOperation : public NodeOperation { +class MathBaseOperation : public MultiThreadedOperation { protected: /** * Prefetched reference to the inputProgram @@ -43,8 +43,24 @@ class MathBaseOperation : public NodeOperation { */ MathBaseOperation(); + /* TODO(manzanilla): to be removed with tiled implementation. */ void clampIfNeeded(float color[4]); + float clamp_when_enabled(float value) + { + if (this->m_useClamp) { + return CLAMPIS(value, 0.0f, 1.0f); + } + return value; + } + + void clamp_when_enabled(float *out) + { + if (this->m_useClamp) { + CLAMP(*out, 0.0f, 1.0f); + } + } + public: /** * Initialize the execution @@ -66,87 +82,151 @@ class MathBaseOperation : public NodeOperation { { this->m_useClamp = value; } + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) final; + + protected: + virtual void update_memory_buffer_partial(BuffersIterator<float> &it) = 0; }; -class MathAddOperation : public MathBaseOperation { +template<template<typename> typename TFunctor> +class MathFunctor2Operation : public MathBaseOperation { + void update_memory_buffer_partial(BuffersIterator<float> &it) final + { + TFunctor functor; + for (; !it.is_end(); ++it) { + *it.out = functor(*it.in(0), *it.in(1)); + clamp_when_enabled(it.out); + } + } +}; + +class MathAddOperation : public MathFunctor2Operation<std::plus> { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; -class MathSubtractOperation : public MathBaseOperation { +class MathSubtractOperation : public MathFunctor2Operation<std::minus> { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; -class MathMultiplyOperation : public MathBaseOperation { +class MathMultiplyOperation : public MathFunctor2Operation<std::multiplies> { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathDivideOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathSineOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathCosineOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathTangentOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathHyperbolicSineOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathHyperbolicCosineOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathHyperbolicTangentOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathArcSineOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathArcCosineOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathArcTangentOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathPowerOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathLogarithmOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathMinimumOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathMaximumOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathRoundOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; -class MathLessThanOperation : public MathBaseOperation { +class MathLessThanOperation : public MathFunctor2Operation<std::less> { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; -class MathGreaterThanOperation : public MathBaseOperation { +class MathGreaterThanOperation : public MathFunctor2Operation<std::greater> { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; @@ -154,101 +234,161 @@ class MathGreaterThanOperation : public MathBaseOperation { class MathModuloOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathAbsoluteOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathRadiansOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathDegreesOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathArcTan2Operation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathFloorOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathCeilOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathFractOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathSqrtOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathInverseSqrtOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathSignOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathExponentOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathTruncOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathSnapOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathWrapOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathPingpongOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathCompareOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathMultiplyAddOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathSmoothMinOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; class MathSmoothMaxOperation : public MathBaseOperation { public: void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + protected: + void update_memory_buffer_partial(BuffersIterator<float> &it) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cc b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc index c8e045ea117..d3424959061 100644 --- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cc +++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc @@ -128,4 +128,51 @@ bool MovieDistortionOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } +void MovieDistortionOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + BLI_assert(input_idx == 0); + UNUSED_VARS_NDEBUG(input_idx); + r_input_area.xmin = output_area.xmin - m_margin[0]; + r_input_area.ymin = output_area.ymin - m_margin[1]; + r_input_area.xmax = output_area.xmax + m_margin[0]; + r_input_area.ymax = output_area.ymax + m_margin[1]; +} + +void MovieDistortionOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input_img = inputs[0]; + if (this->m_distortion == nullptr) { + output->copy_from(input_img, area); + return; + } + + /* `float overscan = 0.0f;` */ + const float pixel_aspect = this->m_pixel_aspect; + const float w = (float)this->m_width /* `/ (1 + overscan)` */; + const float h = (float)this->m_height /* `/ (1 + overscan)` */; + const float aspx = w / (float)this->m_calibration_width; + const float aspy = h / (float)this->m_calibration_height; + float xy[2]; + float distorted_xy[2]; + for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) { + xy[0] = (it.x /* `- 0.5 * overscan * w` */) / aspx; + xy[1] = (it.y /* `- 0.5 * overscan * h` */) / aspy / pixel_aspect; + + if (this->m_apply) { + BKE_tracking_distortion_undistort_v2(this->m_distortion, xy, distorted_xy); + } + else { + BKE_tracking_distortion_distort_v2(this->m_distortion, xy, distorted_xy); + } + + const float u = distorted_xy[0] * aspx /* `+ 0.5 * overscan * w` */; + const float v = (distorted_xy[1] * aspy /* `+ 0.5 * overscan * h` */) * pixel_aspect; + input_img->read_elem_bilinear(u, v, it.out); + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.h b/source/blender/compositor/operations/COM_MovieDistortionOperation.h index 631a62f7ebf..69c2f9c269c 100644 --- a/source/blender/compositor/operations/COM_MovieDistortionOperation.h +++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.h @@ -18,7 +18,7 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" #include "DNA_movieclip_types.h" #include "MEM_guardedalloc.h" @@ -26,7 +26,7 @@ namespace blender::compositor { -class MovieDistortionOperation : public NodeOperation { +class MovieDistortionOperation : public MultiThreadedOperation { private: SocketReader *m_inputOperation; MovieClip *m_movieClip; @@ -58,6 +58,11 @@ class MovieDistortionOperation : public NodeOperation { bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; + + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc index 3577860b93d..d2a06ddd7c4 100644 --- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc +++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc @@ -16,6 +16,7 @@ */ #include "COM_PlaneCornerPinOperation.h" +#include "COM_ConstantOperation.h" #include "COM_ReadBufferOperation.h" #include "MEM_guardedalloc.h" @@ -28,6 +29,11 @@ namespace blender::compositor { +constexpr int LOWER_LEFT_CORNER_INDEX = 0; +constexpr int LOWER_RIGHT_CORNER_INDEX = 1; +constexpr int UPPER_RIGHT_CORNER_INDEX = 2; +constexpr int UPPER_LEFT_CORNER_INDEX = 3; + static bool check_corners(float corners[4][2]) { int i, next, prev; @@ -58,6 +64,7 @@ static bool check_corners(float corners[4][2]) return true; } +/* TODO(manzanilla): to be removed with tiled implementation. */ static void readCornersFromSockets(rcti *rect, SocketReader *readers[4], float corners[4][2]) { for (int i = 0; i < 4; i++) { @@ -87,6 +94,53 @@ static void readCornersFromSockets(rcti *rect, SocketReader *readers[4], float c } } +static void set_default_corner(const int corner_idx, float r_corner[2]) +{ + BLI_assert(corner_idx >= 0 && corner_idx < 4); + switch (corner_idx) { + case LOWER_LEFT_CORNER_INDEX: + r_corner[0] = 0.0f; + r_corner[1] = 0.0f; + break; + case LOWER_RIGHT_CORNER_INDEX: + r_corner[0] = 1.0f; + r_corner[1] = 0.0f; + break; + case UPPER_RIGHT_CORNER_INDEX: + r_corner[0] = 1.0f; + r_corner[1] = 1.0f; + break; + case UPPER_LEFT_CORNER_INDEX: + r_corner[0] = 0.0f; + r_corner[1] = 1.0f; + break; + } +} + +static void read_input_corners(NodeOperation *op, const int first_input_idx, float r_corners[4][2]) +{ + for (const int i : IndexRange(4)) { + NodeOperation *input = op->get_input_operation(i + first_input_idx); + if (input->get_flags().is_constant_operation) { + ConstantOperation *corner_input = static_cast<ConstantOperation *>(input); + copy_v2_v2(r_corners[i], corner_input->get_constant_elem()); + } + else { + set_default_corner(i, r_corners[i]); + } + } + + /* Convexity check: concave corners need to be prevented, otherwise + * #BKE_tracking_homography_between_two_quads will freeze. */ + if (!check_corners(r_corners)) { + /* Revert to default corners. There could be a more elegant solution, + * this prevents freezing at least. */ + for (const int i : IndexRange(4)) { + set_default_corner(i, r_corners[i]); + } + } +} + /* ******** PlaneCornerPinMaskOperation ******** */ PlaneCornerPinMaskOperation::PlaneCornerPinMaskOperation() : m_corners_ready(false) @@ -103,6 +157,17 @@ PlaneCornerPinMaskOperation::PlaneCornerPinMaskOperation() : m_corners_ready(fal flags.complex = true; } +void PlaneCornerPinMaskOperation::init_data() +{ + if (execution_model_ == eExecutionModel::FullFrame) { + float corners[4][2]; + read_input_corners(this, 0, corners); + calculateCorners(corners, true, 0); + } +} + +/* TODO(manzanilla): to be removed with tiled implementation. Same for #deinitExecution and do the + * same on #PlaneCornerPinWarpImageOperation. */ void PlaneCornerPinMaskOperation::initExecution() { PlaneDistortMaskOperation::initExecution(); @@ -147,10 +212,22 @@ void *PlaneCornerPinMaskOperation::initializeTileData(rcti *rect) void PlaneCornerPinMaskOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) { + if (execution_model_ == eExecutionModel::FullFrame) { + /* Determine inputs resolution. */ + PlaneDistortMaskOperation::determineResolution(resolution, preferredResolution); + } resolution[0] = preferredResolution[0]; resolution[1] = preferredResolution[1]; } +void PlaneCornerPinMaskOperation::get_area_of_interest(const int UNUSED(input_idx), + const rcti &UNUSED(output_area), + rcti &r_input_area) +{ + /* All corner inputs are used as constants. */ + r_input_area = COM_SINGLE_ELEM_AREA; +} + /* ******** PlaneCornerPinWarpImageOperation ******** */ PlaneCornerPinWarpImageOperation::PlaneCornerPinWarpImageOperation() : m_corners_ready(false) @@ -161,6 +238,15 @@ PlaneCornerPinWarpImageOperation::PlaneCornerPinWarpImageOperation() : m_corners addInputSocket(DataType::Vector); } +void PlaneCornerPinWarpImageOperation::init_data() +{ + if (execution_model_ == eExecutionModel::FullFrame) { + float corners[4][2]; + read_input_corners(this, 1, corners); + calculateCorners(corners, true, 0); + } +} + void PlaneCornerPinWarpImageOperation::initExecution() { PlaneDistortWarpImageOperation::initExecution(); @@ -227,4 +313,17 @@ bool PlaneCornerPinWarpImageOperation::determineDependingAreaOfInterest( #endif } +void PlaneCornerPinWarpImageOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + if (input_idx == 0) { + PlaneDistortWarpImageOperation::get_area_of_interest(input_idx, output_area, r_input_area); + } + else { + /* Corner inputs are used as constants. */ + r_input_area = COM_SINGLE_ELEM_AREA; + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h index 91c0cd9e16b..2831e937147 100644 --- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h +++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h @@ -31,11 +31,13 @@ namespace blender::compositor { class PlaneCornerPinMaskOperation : public PlaneDistortMaskOperation { private: + /* TODO(manzanilla): to be removed with tiled implementation. */ bool m_corners_ready; public: PlaneCornerPinMaskOperation(); + void init_data() override; void initExecution() override; void deinitExecution() override; @@ -43,6 +45,8 @@ class PlaneCornerPinMaskOperation : public PlaneDistortMaskOperation { void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) override; + + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; }; class PlaneCornerPinWarpImageOperation : public PlaneDistortWarpImageOperation { @@ -52,6 +56,7 @@ class PlaneCornerPinWarpImageOperation : public PlaneDistortWarpImageOperation { public: PlaneCornerPinWarpImageOperation(); + void init_data() override; void initExecution() override; void deinitExecution() override; @@ -60,6 +65,8 @@ class PlaneCornerPinWarpImageOperation : public PlaneDistortWarpImageOperation { bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; + + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc index 4edcc206f5b..ccabb3cf11c 100644 --- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc +++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc @@ -85,8 +85,9 @@ void PlaneDistortWarpImageOperation::calculateCorners(const float corners[4][2], { PlaneDistortBaseOperation::calculateCorners(corners, normalized, sample); - const int width = this->m_pixelReader->getWidth(); - const int height = this->m_pixelReader->getHeight(); + const NodeOperation *image = get_input_operation(0); + const int width = image->getWidth(); + const int height = image->getHeight(); float frame_corners[4][2] = { {0.0f, 0.0f}, {(float)width, 0.0f}, {(float)width, (float)height}, {0.0f, (float)height}}; MotionSample *sample_data = &this->m_samples[sample]; @@ -127,6 +128,34 @@ void PlaneDistortWarpImageOperation::executePixelSampled(float output[4], } } +void PlaneDistortWarpImageOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input_img = inputs[0]; + float uv[2]; + float deriv[2][2]; + BuffersIterator<float> it = output->iterate_with({}, area); + if (this->m_motion_blur_samples == 1) { + for (; !it.is_end(); ++it) { + warpCoord(it.x, it.y, this->m_samples[0].perspectiveMatrix, uv, deriv); + input_img->read_elem_filtered(uv[0], uv[1], deriv[0], deriv[1], it.out); + } + } + else { + for (; !it.is_end(); ++it) { + zero_v4(it.out); + for (const int sample : IndexRange(this->m_motion_blur_samples)) { + float color[4]; + warpCoord(it.x, it.y, this->m_samples[sample].perspectiveMatrix, uv, deriv); + input_img->read_elem_filtered(uv[0], uv[1], deriv[0], deriv[1], color); + add_v4_v4(it.out, color); + } + mul_v4_fl(it.out, 1.0f / (float)this->m_motion_blur_samples); + } + } +} + bool PlaneDistortWarpImageOperation::determineDependingAreaOfInterest( rcti *input, ReadBufferOperation *readOperation, rcti *output) { @@ -157,6 +186,51 @@ bool PlaneDistortWarpImageOperation::determineDependingAreaOfInterest( return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } +void PlaneDistortWarpImageOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + if (input_idx != 0) { + r_input_area = output_area; + return; + } + + /* TODO: figure out the area needed for warping and EWA filtering. */ + r_input_area.xmin = 0; + r_input_area.ymin = 0; + r_input_area.xmax = get_input_operation(0)->getWidth(); + r_input_area.ymax = get_input_operation(0)->getHeight(); + +/* Old implementation but resulting coordinates are way out of input operation bounds and in some + * cases the area result may incorrectly cause cropping. */ +#if 0 + float min[2], max[2]; + INIT_MINMAX2(min, max); + for (int sample = 0; sample < this->m_motion_blur_samples; sample++) { + float UVs[4][2]; + float deriv[2][2]; + MotionSample *sample_data = &this->m_samples[sample]; + /* TODO(sergey): figure out proper way to do this. */ + warpCoord( + output_area.xmin - 2, output_area.ymin - 2, sample_data->perspectiveMatrix, UVs[0], deriv); + warpCoord( + output_area.xmax + 2, output_area.ymin - 2, sample_data->perspectiveMatrix, UVs[1], deriv); + warpCoord( + output_area.xmax + 2, output_area.ymax + 2, sample_data->perspectiveMatrix, UVs[2], deriv); + warpCoord( + output_area.xmin - 2, output_area.ymax + 2, sample_data->perspectiveMatrix, UVs[3], deriv); + for (int i = 0; i < 4; i++) { + minmax_v2v2_v2(min, max, UVs[i]); + } + } + + r_input_area.xmin = min[0] - 1; + r_input_area.ymin = min[1] - 1; + r_input_area.xmax = max[0] + 1; + r_input_area.ymax = max[1] + 1; +#endif +} + /* ******** PlaneDistort Mask ******** */ PlaneDistortMaskOperation::PlaneDistortMaskOperation() : PlaneDistortBaseOperation() @@ -219,4 +293,41 @@ void PlaneDistortMaskOperation::executePixelSampled(float output[4], } } +void PlaneDistortMaskOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> UNUSED(inputs)) +{ + for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) { + int inside_count = 0; + for (const int motion_sample : IndexRange(this->m_motion_blur_samples)) { + MotionSample &sample = this->m_samples[motion_sample]; + inside_count += get_jitter_samples_inside_count(it.x, it.y, sample); + } + *it.out = (float)inside_count / (this->m_osa * this->m_motion_blur_samples); + } +} + +int PlaneDistortMaskOperation::get_jitter_samples_inside_count(int x, + int y, + MotionSample &sample_data) +{ + float point[2]; + int inside_count = 0; + for (int sample = 0; sample < this->m_osa; sample++) { + point[0] = x + this->m_jitter[sample][0]; + point[1] = y + this->m_jitter[sample][1]; + if (isect_point_tri_v2(point, + sample_data.frameSpaceCorners[0], + sample_data.frameSpaceCorners[1], + sample_data.frameSpaceCorners[2]) || + isect_point_tri_v2(point, + sample_data.frameSpaceCorners[0], + sample_data.frameSpaceCorners[2], + sample_data.frameSpaceCorners[3])) { + inside_count++; + } + } + return inside_count; +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h index cc6e4d00d71..3ef9c1dfab8 100644 --- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h +++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h @@ -20,7 +20,7 @@ #include <string.h> -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" #include "DNA_movieclip_types.h" #include "DNA_tracking_types.h" @@ -32,7 +32,7 @@ namespace blender::compositor { #define PLANE_DISTORT_MAX_SAMPLES 64 -class PlaneDistortBaseOperation : public NodeOperation { +class PlaneDistortBaseOperation : public MultiThreadedOperation { protected: struct MotionSample { float frameSpaceCorners[4][2]; /* Corners coordinates in pixel space. */ @@ -78,6 +78,11 @@ class PlaneDistortWarpImageOperation : public PlaneDistortBaseOperation { bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; + + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; class PlaneDistortMaskOperation : public PlaneDistortBaseOperation { @@ -91,6 +96,13 @@ class PlaneDistortMaskOperation : public PlaneDistortBaseOperation { void initExecution() override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; + + private: + int get_jitter_samples_inside_count(int x, int y, MotionSample &sample_data); }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cc b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc index 0884f2ad979..bf24f843ca2 100644 --- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cc +++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc @@ -101,18 +101,40 @@ void PlaneTrackCommon::determineResolution(unsigned int resolution[2], /* ******** PlaneTrackMaskOperation ******** */ +void PlaneTrackMaskOperation::init_data() +{ + PlaneDistortMaskOperation::init_data(); + if (execution_model_ == eExecutionModel::FullFrame) { + PlaneTrackCommon::read_and_calculate_corners(this); + } +} + +/* TODO(manzanilla): to be removed with tiled implementation. */ void PlaneTrackMaskOperation::initExecution() { PlaneDistortMaskOperation::initExecution(); - PlaneTrackCommon::read_and_calculate_corners(this); + if (execution_model_ == eExecutionModel::Tiled) { + PlaneTrackCommon::read_and_calculate_corners(this); + } } /* ******** PlaneTrackWarpImageOperation ******** */ +void PlaneTrackWarpImageOperation::init_data() +{ + PlaneDistortWarpImageOperation::init_data(); + if (execution_model_ == eExecutionModel::FullFrame) { + PlaneTrackCommon::read_and_calculate_corners(this); + } +} + +/* TODO(manzanilla): to be removed with tiled implementation. */ void PlaneTrackWarpImageOperation::initExecution() { PlaneDistortWarpImageOperation::initExecution(); - PlaneTrackCommon::read_and_calculate_corners(this); + if (execution_model_ == eExecutionModel::Tiled) { + PlaneTrackCommon::read_and_calculate_corners(this); + } } } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.h b/source/blender/compositor/operations/COM_PlaneTrackOperation.h index 3bae230aa06..d2027755162 100644 --- a/source/blender/compositor/operations/COM_PlaneTrackOperation.h +++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.h @@ -73,6 +73,8 @@ class PlaneTrackMaskOperation : public PlaneDistortMaskOperation, public PlaneTr { } + void init_data() override; + void initExecution() override; void determineResolution(unsigned int resolution[2], @@ -92,6 +94,8 @@ class PlaneTrackWarpImageOperation : public PlaneDistortWarpImageOperation, { } + void init_data() override; + void initExecution() override; void determineResolution(unsigned int resolution[2], diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc index 93702d3f0cf..fcab5dd5751 100644 --- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc +++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc @@ -17,6 +17,8 @@ */ #include "COM_ProjectorLensDistortionOperation.h" +#include "COM_ConstantOperation.h" + #include "BLI_math.h" #include "BLI_utildefines.h" @@ -32,6 +34,20 @@ ProjectorLensDistortionOperation::ProjectorLensDistortionOperation() this->m_dispersionAvailable = false; this->m_dispersion = 0.0f; } + +void ProjectorLensDistortionOperation::init_data() +{ + if (execution_model_ == eExecutionModel::FullFrame) { + NodeOperation *dispersion_input = get_input_operation(1); + if (dispersion_input->get_flags().is_constant_operation) { + this->m_dispersion = + static_cast<ConstantOperation *>(dispersion_input)->get_constant_elem()[0]; + } + this->m_kr = 0.25f * max_ff(min_ff(this->m_dispersion, 1.0f), 0.0f); + this->m_kr2 = this->m_kr * 20; + } +} + void ProjectorLensDistortionOperation::initExecution() { this->initMutex(); @@ -97,6 +113,7 @@ bool ProjectorLensDistortionOperation::determineDependingAreaOfInterest( return false; } +/* TODO(manzanilla): to be removed with tiled implementation. */ void ProjectorLensDistortionOperation::updateDispersion() { if (this->m_dispersionAvailable) { @@ -114,4 +131,41 @@ void ProjectorLensDistortionOperation::updateDispersion() this->unlockMutex(); } +void ProjectorLensDistortionOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + if (input_idx == 1) { + /* Dispersion input is used as constant only. */ + r_input_area = COM_SINGLE_ELEM_AREA; + return; + } + + r_input_area.ymax = output_area.ymax; + r_input_area.ymin = output_area.ymin; + r_input_area.xmin = output_area.xmin - this->m_kr2 - 2; + r_input_area.xmax = output_area.xmax + this->m_kr2 + 2; +} + +void ProjectorLensDistortionOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input_image = inputs[0]; + const float height = this->getHeight(); + const float width = this->getWidth(); + float color[4]; + for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) { + const float v = (it.y + 0.5f) / height; + const float u = (it.x + 0.5f) / width; + input_image->read_elem_bilinear((u * width + this->m_kr2) - 0.5f, v * height - 0.5f, color); + it.out[0] = color[0]; + input_image->read_elem(it.x, it.y, color); + it.out[1] = color[1]; + input_image->read_elem_bilinear((u * width - this->m_kr2) - 0.5f, v * height - 0.5f, color); + it.out[2] = color[2]; + it.out[3] = 1.0f; + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h index bce61d3de15..7c7626bf271 100644 --- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h +++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h @@ -18,12 +18,12 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" #include "DNA_node_types.h" namespace blender::compositor { -class ProjectorLensDistortionOperation : public NodeOperation { +class ProjectorLensDistortionOperation : public MultiThreadedOperation { private: /** * Cached reference to the inputProgram @@ -31,6 +31,7 @@ class ProjectorLensDistortionOperation : public NodeOperation { SocketReader *m_inputProgram; float m_dispersion; + /* TODO(manzanilla): to be removed with tiled implementation. */ bool m_dispersionAvailable; float m_kr, m_kr2; @@ -43,6 +44,7 @@ class ProjectorLensDistortionOperation : public NodeOperation { */ void executePixel(float output[4], int x, int y, void *data) override; + void init_data() override; /** * Initialize the execution */ @@ -59,6 +61,11 @@ class ProjectorLensDistortionOperation : public NodeOperation { rcti *output) override; void updateDispersion(); + + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_RotateOperation.cc b/source/blender/compositor/operations/COM_RotateOperation.cc index 4fb3d324992..e3c482c15cb 100644 --- a/source/blender/compositor/operations/COM_RotateOperation.cc +++ b/source/blender/compositor/operations/COM_RotateOperation.cc @@ -17,6 +17,8 @@ */ #include "COM_RotateOperation.h" +#include "COM_ConstantOperation.h" + #include "BLI_math.h" namespace blender::compositor { @@ -31,13 +33,50 @@ RotateOperation::RotateOperation() this->m_degreeSocket = nullptr; this->m_doDegree2RadConversion = false; this->m_isDegreeSet = false; + sampler_ = PixelSampler::Bilinear; +} + +void RotateOperation::get_area_rotation_bounds(const rcti &area, + const float center_x, + const float center_y, + const float sine, + const float cosine, + rcti &r_bounds) +{ + const float dxmin = area.xmin - center_x; + const float dymin = area.ymin - center_y; + const float dxmax = area.xmax - center_x; + const float dymax = area.ymax - center_y; + + const float x1 = center_x + (cosine * dxmin + sine * dymin); + const float x2 = center_x + (cosine * dxmax + sine * dymin); + const float x3 = center_x + (cosine * dxmin + sine * dymax); + const float x4 = center_x + (cosine * dxmax + sine * dymax); + const float y1 = center_y + (-sine * dxmin + cosine * dymin); + const float y2 = center_y + (-sine * dxmax + cosine * dymin); + const float y3 = center_y + (-sine * dxmin + cosine * dymax); + const float y4 = center_y + (-sine * dxmax + cosine * dymax); + const float minx = MIN2(x1, MIN2(x2, MIN2(x3, x4))); + const float maxx = MAX2(x1, MAX2(x2, MAX2(x3, x4))); + const float miny = MIN2(y1, MIN2(y2, MIN2(y3, y4))); + const float maxy = MAX2(y1, MAX2(y2, MAX2(y3, y4))); + + r_bounds.xmin = floor(minx); + r_bounds.xmax = ceil(maxx); + r_bounds.ymin = floor(miny); + r_bounds.ymax = ceil(maxy); +} + +void RotateOperation::init_data() +{ + this->m_centerX = (getWidth() - 1) / 2.0; + this->m_centerY = (getHeight() - 1) / 2.0; } + void RotateOperation::initExecution() { this->m_imageSocket = this->getInputSocketReader(0); this->m_degreeSocket = this->getInputSocketReader(1); - this->m_centerX = (getWidth() - 1) / 2.0; - this->m_centerY = (getHeight() - 1) / 2.0; } void RotateOperation::deinitExecution() @@ -50,7 +89,19 @@ inline void RotateOperation::ensureDegree() { if (!this->m_isDegreeSet) { float degree[4]; - this->m_degreeSocket->readSampled(degree, 0, 0, PixelSampler::Nearest); + switch (execution_model_) { + case eExecutionModel::Tiled: + this->m_degreeSocket->readSampled(degree, 0, 0, PixelSampler::Nearest); + break; + case eExecutionModel::FullFrame: + NodeOperation *degree_op = getInputOperation(DEGREE_INPUT_INDEX); + const bool is_constant_degree = degree_op->get_flags().is_constant_operation; + degree[0] = is_constant_degree ? + static_cast<ConstantOperation *>(degree_op)->get_constant_elem()[0] : + 0.0f; + break; + } + double rad; if (this->m_doDegree2RadConversion) { rad = DEG2RAD((double)degree[0]); @@ -108,4 +159,33 @@ bool RotateOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } +void RotateOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + if (input_idx == DEGREE_INPUT_INDEX) { + /* Degrees input is always used as constant. */ + r_input_area = COM_SINGLE_ELEM_AREA; + return; + } + + ensureDegree(); + get_area_rotation_bounds(output_area, m_centerX, m_centerY, m_sine, m_cosine, r_input_area); + expand_area_for_sampler(r_input_area, sampler_); +} + +void RotateOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + ensureDegree(); + const MemoryBuffer *input_img = inputs[IMAGE_INPUT_INDEX]; + for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) { + float x = it.x; + float y = it.y; + rotate_coords(x, y, m_centerX, m_centerY, m_sine, m_cosine); + input_img->read_elem_sampled(x, y, sampler_, it.out); + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_RotateOperation.h b/source/blender/compositor/operations/COM_RotateOperation.h index d76507f9816..f0de699f9ce 100644 --- a/source/blender/compositor/operations/COM_RotateOperation.h +++ b/source/blender/compositor/operations/COM_RotateOperation.h @@ -18,12 +18,15 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { -class RotateOperation : public NodeOperation { +class RotateOperation : public MultiThreadedOperation { private: + constexpr static int IMAGE_INPUT_INDEX = 0; + constexpr static int DEGREE_INPUT_INDEX = 1; + SocketReader *m_imageSocket; SocketReader *m_degreeSocket; float m_centerX; @@ -32,21 +35,51 @@ class RotateOperation : public NodeOperation { float m_sine; bool m_doDegree2RadConversion; bool m_isDegreeSet; + PixelSampler sampler_; public: RotateOperation(); + + static void rotate_coords( + float &x, float &y, float center_x, float center_y, float sine, float cosine) + { + const float dx = x - center_x; + const float dy = y - center_y; + x = center_x + (cosine * dx + sine * dy); + y = center_y + (-sine * dx + cosine * dy); + } + + static void get_area_rotation_bounds(const rcti &area, + const float center_x, + const float center_y, + const float sine, + const float cosine, + rcti &r_bounds); + bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + void init_data() override; void initExecution() override; void deinitExecution() override; + void setDoDegree2RadConversion(bool abool) { this->m_doDegree2RadConversion = abool; } + void set_sampler(PixelSampler sampler) + { + sampler_ = sampler; + } + void ensureDegree(); + + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cc b/source/blender/compositor/operations/COM_ScaleOperation.cc index 5410b2c832a..ef34bc7bee6 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.cc +++ b/source/blender/compositor/operations/COM_ScaleOperation.cc @@ -74,17 +74,18 @@ float ScaleOperation::get_constant_scale_y() return get_constant_scale(2, get_relative_scale_y_factor()); } -BLI_INLINE float scale_coord(const int coord, const float center, const float relative_scale) +void ScaleOperation::scale_area( + rcti &rect, float center_x, float center_y, float scale_x, float scale_y) { - return center + (coord - center) / relative_scale; + rect.xmin = scale_coord(rect.xmin, center_x, scale_x); + rect.xmax = scale_coord(rect.xmax, center_x, scale_x); + rect.ymin = scale_coord(rect.ymin, center_y, scale_y); + rect.ymax = scale_coord(rect.ymax, center_y, scale_y); } void ScaleOperation::scale_area(rcti &rect, float scale_x, float scale_y) { - rect.xmin = scale_coord(rect.xmin, m_centerX, scale_x); - rect.xmax = scale_coord(rect.xmax, m_centerX, scale_x); - rect.ymin = scale_coord(rect.ymin, m_centerY, scale_y); - rect.ymax = scale_coord(rect.ymax, m_centerY, scale_y); + scale_area(rect, m_centerX, m_centerY, scale_x, scale_y); } void ScaleOperation::init_data() diff --git a/source/blender/compositor/operations/COM_ScaleOperation.h b/source/blender/compositor/operations/COM_ScaleOperation.h index 62a2cabc8e6..65762d1ce62 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.h +++ b/source/blender/compositor/operations/COM_ScaleOperation.h @@ -46,6 +46,9 @@ class BaseScaleOperation : public MultiThreadedOperation { }; class ScaleOperation : public BaseScaleOperation { + public: + static constexpr float MIN_SCALE = 0.0001f; + protected: SocketReader *m_inputOperation; SocketReader *m_inputXOperation; @@ -57,6 +60,12 @@ class ScaleOperation : public BaseScaleOperation { ScaleOperation(); ScaleOperation(DataType data_type); + static float scale_coord(const float coord, const float center, const float relative_scale) + { + return center + (coord - center) / MAX2(relative_scale, MIN_SCALE); + } + static void scale_area(rcti &rect, float center_x, float center_y, float scale_x, float scale_y); + void init_data() override; void initExecution() override; void deinitExecution() override; diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc index 634fe66b0dd..1f503051349 100644 --- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc +++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc @@ -17,6 +17,7 @@ */ #include "COM_ScreenLensDistortionOperation.h" +#include "COM_ConstantOperation.h" #include "BLI_math.h" #include "BLI_rand.h" @@ -53,6 +54,35 @@ void ScreenLensDistortionOperation::setDispersion(float dispersion) m_dispersion_const = true; } +void ScreenLensDistortionOperation::init_data() +{ + this->m_cx = 0.5f * (float)getWidth(); + this->m_cy = 0.5f * (float)getHeight(); + + switch (execution_model_) { + case eExecutionModel::FullFrame: { + NodeOperation *distortion_op = get_input_operation(1); + NodeOperation *dispersion_op = get_input_operation(2); + if (!m_distortion_const && distortion_op->get_flags().is_constant_operation) { + m_distortion = static_cast<ConstantOperation *>(distortion_op)->get_constant_elem()[0]; + } + if (!m_dispersion_const && distortion_op->get_flags().is_constant_operation) { + m_dispersion = static_cast<ConstantOperation *>(dispersion_op)->get_constant_elem()[0]; + } + updateVariables(m_distortion, m_dispersion); + break; + } + case eExecutionModel::Tiled: { + /* If both are constant, init variables once. */ + if (m_distortion_const && m_dispersion_const) { + updateVariables(m_distortion, m_dispersion); + m_variables_ready = true; + } + break; + } + } +} + void ScreenLensDistortionOperation::initExecution() { this->m_inputProgram = this->getInputSocketReader(0); @@ -61,15 +91,6 @@ void ScreenLensDistortionOperation::initExecution() uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX); rng_seed ^= (uint)POINTER_AS_INT(m_inputProgram); this->m_rng = BLI_rng_new(rng_seed); - - this->m_cx = 0.5f * (float)getWidth(); - this->m_cy = 0.5f * (float)getHeight(); - - /* if both are constant, init variables once */ - if (m_distortion_const && m_dispersion_const) { - updateVariables(m_distortion, m_dispersion); - m_variables_ready = true; - } } void *ScreenLensDistortionOperation::initializeTileData(rcti * /*rect*/) @@ -130,7 +151,7 @@ bool ScreenLensDistortionOperation::get_delta(float r_sq, return false; } -void ScreenLensDistortionOperation::accumulate(MemoryBuffer *buffer, +void ScreenLensDistortionOperation::accumulate(const MemoryBuffer *buffer, int a, int b, float r_sq, @@ -154,7 +175,14 @@ void ScreenLensDistortionOperation::accumulate(MemoryBuffer *buffer, float xy[2]; distort_uv(uv, t, xy); - buffer->readBilinear(color, xy[0], xy[1]); + switch (execution_model_) { + case eExecutionModel::Tiled: + buffer->readBilinear(color, xy[0], xy[1]); + break; + case eExecutionModel::FullFrame: + buffer->read_elem_bilinear(xy[0], xy[1], color); + break; + } sum[a] += (1.0f - tz) * color[a]; sum[b] += (tz)*color[b]; @@ -354,4 +382,143 @@ void ScreenLensDistortionOperation::updateVariables(float distortion, float disp mul_v3_v3fl(m_k4, m_k, 4.0f); } +void ScreenLensDistortionOperation::get_area_of_interest(const int input_idx, + const rcti &UNUSED(output_area), + rcti &r_input_area) +{ + if (input_idx != 0) { + /* Dispersion and distortion inputs are used as constants only. */ + r_input_area = COM_SINGLE_ELEM_AREA; + } + + /* XXX the original method of estimating the area-of-interest does not work + * it assumes a linear increase/decrease of mapped coordinates, which does not + * yield correct results for the area and leaves uninitialized buffer areas. + * So now just use the full image area, which may not be as efficient but works at least ... + */ +#if 1 + NodeOperation *image = getInputOperation(0); + r_input_area.xmax = image->getWidth(); + r_input_area.xmin = 0; + r_input_area.ymax = image->getHeight(); + r_input_area.ymin = 0; + +#else /* Original method in tiled implementation. */ + rcti newInput; + const float margin = 2; + + BLI_rcti_init_minmax(&newInput); + + if (m_dispersion_const && m_distortion_const) { + /* update from fixed distortion/dispersion */ +# define UPDATE_INPUT(x, y) \ + { \ + float coords[6]; \ + determineUV(coords, x, y); \ + newInput.xmin = min_ffff(newInput.xmin, coords[0], coords[2], coords[4]); \ + newInput.ymin = min_ffff(newInput.ymin, coords[1], coords[3], coords[5]); \ + newInput.xmax = max_ffff(newInput.xmax, coords[0], coords[2], coords[4]); \ + newInput.ymax = max_ffff(newInput.ymax, coords[1], coords[3], coords[5]); \ + } \ + (void)0 + + UPDATE_INPUT(input->xmin, input->xmax); + UPDATE_INPUT(input->xmin, input->ymax); + UPDATE_INPUT(input->xmax, input->ymax); + UPDATE_INPUT(input->xmax, input->ymin); + +# undef UPDATE_INPUT + } + else { + /* use maximum dispersion 1.0 if not const */ + float dispersion = m_dispersion_const ? m_dispersion : 1.0f; + +# define UPDATE_INPUT(x, y, distortion) \ + { \ + float coords[6]; \ + updateVariables(distortion, dispersion); \ + determineUV(coords, x, y); \ + newInput.xmin = min_ffff(newInput.xmin, coords[0], coords[2], coords[4]); \ + newInput.ymin = min_ffff(newInput.ymin, coords[1], coords[3], coords[5]); \ + newInput.xmax = max_ffff(newInput.xmax, coords[0], coords[2], coords[4]); \ + newInput.ymax = max_ffff(newInput.ymax, coords[1], coords[3], coords[5]); \ + } \ + (void)0 + + if (m_distortion_const) { + /* update from fixed distortion */ + UPDATE_INPUT(input->xmin, input->xmax, m_distortion); + UPDATE_INPUT(input->xmin, input->ymax, m_distortion); + UPDATE_INPUT(input->xmax, input->ymax, m_distortion); + UPDATE_INPUT(input->xmax, input->ymin, m_distortion); + } + else { + /* update from min/max distortion (-1..1) */ + UPDATE_INPUT(input->xmin, input->xmax, -1.0f); + UPDATE_INPUT(input->xmin, input->ymax, -1.0f); + UPDATE_INPUT(input->xmax, input->ymax, -1.0f); + UPDATE_INPUT(input->xmax, input->ymin, -1.0f); + + UPDATE_INPUT(input->xmin, input->xmax, 1.0f); + UPDATE_INPUT(input->xmin, input->ymax, 1.0f); + UPDATE_INPUT(input->xmax, input->ymax, 1.0f); + UPDATE_INPUT(input->xmax, input->ymin, 1.0f); + +# undef UPDATE_INPUT + } + } + + newInput.xmin -= margin; + newInput.ymin -= margin; + newInput.xmax += margin; + newInput.ymax += margin; + + operation = getInputOperation(0); + if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) { + return true; + } + return false; +#endif +} + +void ScreenLensDistortionOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input_image = inputs[0]; + for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) { + float xy[2] = {(float)it.x, (float)it.y}; + float uv[2]; + get_uv(xy, uv); + const float uv_dot = len_squared_v2(uv); + + float delta[3][2]; + const bool valid_r = get_delta(uv_dot, m_k4[0], uv, delta[0]); + const bool valid_g = get_delta(uv_dot, m_k4[1], uv, delta[1]); + const bool valid_b = get_delta(uv_dot, m_k4[2], uv, delta[2]); + if (!(valid_r && valid_g && valid_b)) { + zero_v4(it.out); + continue; + } + + int count[3] = {0, 0, 0}; + float sum[4] = {0, 0, 0, 0}; + accumulate(input_image, 0, 1, uv_dot, uv, delta, sum, count); + accumulate(input_image, 1, 2, uv_dot, uv, delta, sum, count); + + if (count[0]) { + it.out[0] = 2.0f * sum[0] / (float)count[0]; + } + if (count[1]) { + it.out[1] = 2.0f * sum[1] / (float)count[1]; + } + if (count[2]) { + it.out[2] = 2.0f * sum[2] / (float)count[2]; + } + + /* Set alpha. */ + it.out[3] = 1.0f; + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h index 98872bfe142..616fc8883b0 100644 --- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h +++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h @@ -18,14 +18,14 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" #include "DNA_node_types.h" struct RNG; namespace blender::compositor { -class ScreenLensDistortionOperation : public NodeOperation { +class ScreenLensDistortionOperation : public MultiThreadedOperation { private: /** * Cached reference to the inputProgram @@ -50,6 +50,8 @@ class ScreenLensDistortionOperation : public NodeOperation { public: ScreenLensDistortionOperation(); + void init_data() override; + /** * The inner loop of this operation. */ @@ -84,6 +86,11 @@ class ScreenLensDistortionOperation : public NodeOperation { ReadBufferOperation *readOperation, rcti *output) override; + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; + private: void determineUV(float result[6], float x, float y) const; void updateVariables(float distortion, float dispersion); @@ -91,7 +98,7 @@ class ScreenLensDistortionOperation : public NodeOperation { void get_uv(const float xy[2], float uv[2]) const; void distort_uv(const float uv[2], float t, float xy[2]) const; bool get_delta(float r_sq, float k4, const float uv[2], float delta[2]) const; - void accumulate(MemoryBuffer *buffer, + void accumulate(const MemoryBuffer *buffer, int a, int b, float r_sq, diff --git a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc index 24edbc61d40..e4686ffa76d 100644 --- a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc +++ b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc @@ -28,6 +28,7 @@ SetAlphaMultiplyOperation::SetAlphaMultiplyOperation() this->m_inputColor = nullptr; this->m_inputAlpha = nullptr; + this->flags.can_be_constant = true; } void SetAlphaMultiplyOperation::initExecution() @@ -56,4 +57,15 @@ void SetAlphaMultiplyOperation::deinitExecution() this->m_inputAlpha = nullptr; } +void SetAlphaMultiplyOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + const float *color = it.in(0); + const float alpha = *it.in(1); + mul_v4_v4fl(it.out, color, alpha); + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.h b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.h index b4eea659fa2..44885318901 100644 --- a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.h +++ b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.h @@ -18,7 +18,7 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { @@ -27,7 +27,7 @@ namespace blender::compositor { * * `output color.rgba = input color.rgba * input alpha` */ -class SetAlphaMultiplyOperation : public NodeOperation { +class SetAlphaMultiplyOperation : public MultiThreadedOperation { private: SocketReader *m_inputColor; SocketReader *m_inputAlpha; @@ -39,6 +39,10 @@ class SetAlphaMultiplyOperation : public NodeOperation { void initExecution() override; void deinitExecution() override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc index 90bfc814b09..434f5d9b63c 100644 --- a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc +++ b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc @@ -28,6 +28,7 @@ SetAlphaReplaceOperation::SetAlphaReplaceOperation() this->m_inputColor = nullptr; this->m_inputAlpha = nullptr; + this->flags.can_be_constant = true; } void SetAlphaReplaceOperation::initExecution() @@ -54,4 +55,16 @@ void SetAlphaReplaceOperation::deinitExecution() this->m_inputAlpha = nullptr; } +void SetAlphaReplaceOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { + const float *color = it.in(0); + const float alpha = *it.in(1); + copy_v3_v3(it.out, color); + it.out[3] = alpha; + } +} + } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.h b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.h index c84299b6d82..2c2d4cddf5b 100644 --- a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.h +++ b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.h @@ -18,7 +18,7 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" namespace blender::compositor { @@ -26,7 +26,7 @@ namespace blender::compositor { * this program converts an input color to an output value. * it assumes we are in sRGB color space. */ -class SetAlphaReplaceOperation : public NodeOperation { +class SetAlphaReplaceOperation : public MultiThreadedOperation { private: SocketReader *m_inputColor; SocketReader *m_inputAlpha; @@ -44,6 +44,10 @@ class SetAlphaReplaceOperation : public NodeOperation { void initExecution() override; void deinitExecution() override; + + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; } // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_TransformOperation.cc b/source/blender/compositor/operations/COM_TransformOperation.cc new file mode 100644 index 00000000000..2feaa0ae16d --- /dev/null +++ b/source/blender/compositor/operations/COM_TransformOperation.cc @@ -0,0 +1,156 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +#include "COM_TransformOperation.h" +#include "COM_ConstantOperation.h" +#include "COM_RotateOperation.h" +#include "COM_ScaleOperation.h" + +#include "BLI_math.h" + +namespace blender::compositor { + +TransformOperation::TransformOperation() +{ + addInputSocket(DataType::Color); + addInputSocket(DataType::Value); + addInputSocket(DataType::Value); + addInputSocket(DataType::Value); + addInputSocket(DataType::Value); + addOutputSocket(DataType::Color); + translate_factor_x_ = 1.0f; + translate_factor_y_ = 1.0f; + convert_degree_to_rad_ = false; + sampler_ = PixelSampler::Bilinear; + invert_ = false; +} + +void TransformOperation::init_data() +{ + /* Translation. */ + translate_x_ = 0; + NodeOperation *x_op = getInputOperation(X_INPUT_INDEX); + if (x_op->get_flags().is_constant_operation) { + translate_x_ = static_cast<ConstantOperation *>(x_op)->get_constant_elem()[0] * + translate_factor_x_; + } + translate_y_ = 0; + NodeOperation *y_op = getInputOperation(Y_INPUT_INDEX); + if (y_op->get_flags().is_constant_operation) { + translate_y_ = static_cast<ConstantOperation *>(y_op)->get_constant_elem()[0] * + translate_factor_y_; + } + + /* Scaling. */ + scale_center_x_ = getWidth() / 2.0; + scale_center_y_ = getHeight() / 2.0; + constant_scale_ = 1.0f; + NodeOperation *scale_op = getInputOperation(SCALE_INPUT_INDEX); + if (scale_op->get_flags().is_constant_operation) { + constant_scale_ = static_cast<ConstantOperation *>(scale_op)->get_constant_elem()[0]; + } + + /* Rotation. */ + rotate_center_x_ = (getWidth() - 1.0) / 2.0; + rotate_center_y_ = (getHeight() - 1.0) / 2.0; + NodeOperation *degree_op = getInputOperation(DEGREE_INPUT_INDEX); + const bool is_constant_degree = degree_op->get_flags().is_constant_operation; + const float degree = is_constant_degree ? + static_cast<ConstantOperation *>(degree_op)->get_constant_elem()[0] : + 0.0f; + const double rad = convert_degree_to_rad_ ? DEG2RAD((double)degree) : degree; + rotate_cosine_ = cos(rad); + rotate_sine_ = sin(rad); +} + +void TransformOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + switch (input_idx) { + case IMAGE_INPUT_INDEX: { + BLI_rcti_translate(&r_input_area, translate_x_, translate_y_); + ScaleOperation::scale_area( + r_input_area, scale_center_x_, scale_center_y_, constant_scale_, constant_scale_); + RotateOperation::get_area_rotation_bounds(r_input_area, + rotate_center_x_, + rotate_center_y_, + rotate_sine_, + rotate_cosine_, + r_input_area); + expand_area_for_sampler(r_input_area, sampler_); + break; + } + case X_INPUT_INDEX: + case Y_INPUT_INDEX: + case DEGREE_INPUT_INDEX: { + r_input_area = COM_SINGLE_ELEM_AREA; + break; + } + case SCALE_INPUT_INDEX: { + r_input_area = output_area; + break; + } + } +} + +void TransformOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + const MemoryBuffer *input_img = inputs[IMAGE_INPUT_INDEX]; + MemoryBuffer *input_scale = inputs[SCALE_INPUT_INDEX]; + BuffersIterator<float> it = output->iterate_with({input_scale}, area); + if (invert_) { + transform_inverted(it, input_img); + } + else { + transform(it, input_img); + } +} + +void TransformOperation::transform(BuffersIterator<float> &it, const MemoryBuffer *input_img) +{ + for (; !it.is_end(); ++it) { + const float scale = *it.in(0); + float x = it.x - translate_x_; + float y = it.y - translate_y_; + RotateOperation::rotate_coords( + x, y, rotate_center_x_, rotate_center_y_, rotate_sine_, rotate_cosine_); + x = ScaleOperation::scale_coord(x, scale_center_x_, scale); + y = ScaleOperation::scale_coord(y, scale_center_y_, scale); + input_img->read_elem_sampled(x, y, sampler_, it.out); + } +} + +void TransformOperation::transform_inverted(BuffersIterator<float> &it, + const MemoryBuffer *input_img) +{ + for (; !it.is_end(); ++it) { + const float scale = *it.in(0); + float x = ScaleOperation::scale_coord(it.x, scale_center_x_, scale); + float y = ScaleOperation::scale_coord(it.y, scale_center_y_, scale); + RotateOperation::rotate_coords( + x, y, rotate_center_x_, rotate_center_y_, rotate_sine_, rotate_cosine_); + x -= translate_x_; + y -= translate_y_; + input_img->read_elem_sampled(x, y, sampler_, it.out); + } +} + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_TransformOperation.h b/source/blender/compositor/operations/COM_TransformOperation.h new file mode 100644 index 00000000000..480998a0207 --- /dev/null +++ b/source/blender/compositor/operations/COM_TransformOperation.h @@ -0,0 +1,87 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +#pragma once + +#include "COM_MultiThreadedOperation.h" + +namespace blender::compositor { + +class TransformOperation : public MultiThreadedOperation { + private: + constexpr static int IMAGE_INPUT_INDEX = 0; + constexpr static int X_INPUT_INDEX = 1; + constexpr static int Y_INPUT_INDEX = 2; + constexpr static int DEGREE_INPUT_INDEX = 3; + constexpr static int SCALE_INPUT_INDEX = 4; + + float scale_center_x_; + float scale_center_y_; + float rotate_center_x_; + float rotate_center_y_; + float rotate_cosine_; + float rotate_sine_; + float translate_x_; + float translate_y_; + float constant_scale_; + + /* Set variables. */ + PixelSampler sampler_; + bool convert_degree_to_rad_; + float translate_factor_x_; + float translate_factor_y_; + bool invert_; + + public: + TransformOperation(); + + void set_translate_factor_xy(float x, float y) + { + translate_factor_x_ = x; + translate_factor_y_ = y; + } + + void set_convert_rotate_degree_to_rad(bool value) + { + convert_degree_to_rad_ = value; + } + + void set_sampler(PixelSampler sampler) + { + sampler_ = sampler; + } + + void set_invert(bool value) + { + invert_ = value; + } + + void init_data() override; + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; + + private: + /** Translate -> Rotate -> Scale. */ + void transform(BuffersIterator<float> &it, const MemoryBuffer *input_img); + /** Scale -> Rotate -> Translate. */ + void transform_inverted(BuffersIterator<float> &it, const MemoryBuffer *input_img); +}; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc index 19cd5a53084..6af6f5a6244 100644 --- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc +++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc @@ -18,6 +18,7 @@ #include "COM_VariableSizeBokehBlurOperation.h" #include "BLI_math.h" +#include "COM_ExecutionSystem.h" #include "COM_OpenCLDevice.h" #include "RE_pipeline.h" @@ -276,6 +277,166 @@ bool VariableSizeBokehBlurOperation::determineDependingAreaOfInterest( return false; } +void VariableSizeBokehBlurOperation::get_area_of_interest(const int input_idx, + const rcti &output_area, + rcti &r_input_area) +{ + switch (input_idx) { + case IMAGE_INPUT_INDEX: + case SIZE_INPUT_INDEX: { + const float max_dim = MAX2(getWidth(), getHeight()); + const float scalar = m_do_size_scale ? (max_dim / 100.0f) : 1.0f; + const int max_blur_scalar = m_maxBlur * scalar; + r_input_area.xmax = output_area.xmax + max_blur_scalar + 2; + r_input_area.xmin = output_area.xmin - max_blur_scalar - 2; + r_input_area.ymax = output_area.ymax + max_blur_scalar + 2; + r_input_area.ymin = output_area.ymin - max_blur_scalar - 2; + break; + } + case BOKEH_INPUT_INDEX: { + r_input_area.xmax = COM_BLUR_BOKEH_PIXELS; + r_input_area.xmin = 0; + r_input_area.ymax = COM_BLUR_BOKEH_PIXELS; + r_input_area.ymin = 0; + break; + } +#ifdef COM_DEFOCUS_SEARCH + case DEFOCUS_INPUT_INDEX: { + r_input_area.xmax = (output_area.xmax / InverseSearchRadiusOperation::DIVIDER) + 1; + r_input_area.xmin = (output_area.xmin / InverseSearchRadiusOperation::DIVIDER) - 1; + r_input_area.ymax = (output_area.ymax / InverseSearchRadiusOperation::DIVIDER) + 1; + r_input_area.ymin = (output_area.ymin / InverseSearchRadiusOperation::DIVIDER) - 1; + break; + } +#endif + } +} + +struct PixelData { + float multiplier_accum[4]; + float color_accum[4]; + float threshold; + float scalar; + float size_center; + int max_blur_scalar; + int step; + MemoryBuffer *bokeh_input; + MemoryBuffer *size_input; + MemoryBuffer *image_input; + int image_width; + int image_height; +}; + +static void blur_pixel(int x, int y, PixelData &p) +{ + BLI_assert(p.bokeh_input->getWidth() == COM_BLUR_BOKEH_PIXELS); + BLI_assert(p.bokeh_input->getHeight() == COM_BLUR_BOKEH_PIXELS); + +#ifdef COM_DEFOCUS_SEARCH + float search[4]; + inputs[DEFOCUS_INPUT_INDEX]->read_elem_checked(x / InverseSearchRadiusOperation::DIVIDER, + y / InverseSearchRadiusOperation::DIVIDER, + search); + const int minx = search[0]; + const int miny = search[1]; + const int maxx = search[2]; + const int maxy = search[3]; +#else + const int minx = MAX2(x - p.max_blur_scalar, 0); + const int miny = MAX2(y - p.max_blur_scalar, 0); + const int maxx = MIN2(x + p.max_blur_scalar, p.image_width); + const int maxy = MIN2(y + p.max_blur_scalar, p.image_height); +#endif + + const int color_row_stride = p.image_input->row_stride * p.step; + const int color_elem_stride = p.image_input->elem_stride * p.step; + const int size_row_stride = p.size_input->row_stride * p.step; + const int size_elem_stride = p.size_input->elem_stride * p.step; + const float *row_color = p.image_input->get_elem(minx, miny); + const float *row_size = p.size_input->get_elem(minx, miny); + for (int ny = miny; ny < maxy; + ny += p.step, row_size += size_row_stride, row_color += color_row_stride) { + const float dy = ny - y; + const float *size_elem = row_size; + const float *color = row_color; + for (int nx = minx; nx < maxx; + nx += p.step, size_elem += size_elem_stride, color += color_elem_stride) { + if (nx == x && ny == y) { + continue; + } + const float size = MIN2(size_elem[0] * p.scalar, p.size_center); + if (size <= p.threshold) { + continue; + } + const float dx = nx - x; + if (size <= fabsf(dx) || size <= fabsf(dy)) { + continue; + } + + /* XXX: There is no way to ensure bokeh input is an actual bokeh with #COM_BLUR_BOKEH_PIXELS + * size, anything may be connected. Use the real input size and remove asserts? */ + const float u = (float)(COM_BLUR_BOKEH_PIXELS / 2) + + (dx / size) * (float)((COM_BLUR_BOKEH_PIXELS / 2) - 1); + const float v = (float)(COM_BLUR_BOKEH_PIXELS / 2) + + (dy / size) * (float)((COM_BLUR_BOKEH_PIXELS / 2) - 1); + float bokeh[4]; + p.bokeh_input->read_elem_checked(u, v, bokeh); + madd_v4_v4v4(p.color_accum, bokeh, color); + add_v4_v4(p.multiplier_accum, bokeh); + } + } +} + +void VariableSizeBokehBlurOperation::update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) +{ + PixelData p; + p.bokeh_input = inputs[BOKEH_INPUT_INDEX]; + p.size_input = inputs[SIZE_INPUT_INDEX]; + p.image_input = inputs[IMAGE_INPUT_INDEX]; + p.step = QualityStepHelper::getStep(); + p.threshold = m_threshold; + p.image_width = this->getWidth(); + p.image_height = this->getHeight(); + + rcti scalar_area; + this->get_area_of_interest(SIZE_INPUT_INDEX, area, scalar_area); + BLI_rcti_isect(&scalar_area, &p.size_input->get_rect(), &scalar_area); + const float max_size = p.size_input->get_max_value(scalar_area); + + const float max_dim = MAX2(this->getWidth(), this->getHeight()); + p.scalar = m_do_size_scale ? (max_dim / 100.0f) : 1.0f; + p.max_blur_scalar = static_cast<int>(max_size * p.scalar); + CLAMP(p.max_blur_scalar, 1, m_maxBlur); + + for (BuffersIterator<float> it = output->iterate_with({p.image_input, p.size_input}, area); + !it.is_end(); + ++it) { + const float *color = it.in(0); + const float size = *it.in(1); + copy_v4_v4(p.color_accum, color); + copy_v4_fl(p.multiplier_accum, 1.0f); + p.size_center = size * p.scalar; + + if (p.size_center > p.threshold) { + blur_pixel(it.x, it.y, p); + } + + it.out[0] = p.color_accum[0] / p.multiplier_accum[0]; + it.out[1] = p.color_accum[1] / p.multiplier_accum[1]; + it.out[2] = p.color_accum[2] / p.multiplier_accum[2]; + it.out[3] = p.color_accum[3] / p.multiplier_accum[3]; + + /* Blend in out values over the threshold, otherwise we get sharp, ugly transitions. */ + if ((p.size_center > p.threshold) && (p.size_center < p.threshold * 2.0f)) { + /* Factor from 0-1. */ + const float fac = (p.size_center - p.threshold) / p.threshold; + interp_v4_v4v4(it.out, color, it.out, fac); + } + } +} + #ifdef COM_DEFOCUS_SEARCH // InverseSearchRadiusOperation InverseSearchRadiusOperation::InverseSearchRadiusOperation() diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h index baeab6a646e..56b4677087b 100644 --- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h +++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h @@ -18,15 +18,22 @@ #pragma once -#include "COM_NodeOperation.h" +#include "COM_MultiThreadedOperation.h" #include "COM_QualityStepHelper.h" namespace blender::compositor { //#define COM_DEFOCUS_SEARCH -class VariableSizeBokehBlurOperation : public NodeOperation, public QualityStepHelper { +class VariableSizeBokehBlurOperation : public MultiThreadedOperation, public QualityStepHelper { private: + static constexpr int IMAGE_INPUT_INDEX = 0; + static constexpr int BOKEH_INPUT_INDEX = 1; + static constexpr int SIZE_INPUT_INDEX = 2; +#ifdef COM_DEFOCUS_SEARCH + static constexpr int DEFOCUS_INPUT_INDEX = 3; +#endif + int m_maxBlur; float m_threshold; bool m_do_size_scale; /* scale size, matching 'BokehBlurNode' */ @@ -84,8 +91,14 @@ class VariableSizeBokehBlurOperation : public NodeOperation, public QualityStepH MemoryBuffer **inputMemoryBuffers, std::list<cl_mem> *clMemToCleanUp, std::list<cl_kernel> *clKernelsToCleanUp) override; + + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; + void update_memory_buffer_partial(MemoryBuffer *output, + const rcti &area, + Span<MemoryBuffer *> inputs) override; }; +/* Currently unused. If ever used, it needs full-frame implementation. */ #ifdef COM_DEFOCUS_SEARCH class InverseSearchRadiusOperation : public NodeOperation { private: diff --git a/source/blender/draw/engines/image/image_engine.c b/source/blender/draw/engines/image/image_engine.c index 395d50fbc6b..b4c0ade380e 100644 --- a/source/blender/draw/engines/image/image_engine.c +++ b/source/blender/draw/engines/image/image_engine.c @@ -111,35 +111,52 @@ static void space_image_gpu_texture_get(Image *image, /* Update multi-index and pass for the current eye. */ BKE_image_multilayer_index(image->rr, &sima->iuser); } - BKE_image_multiview_index(image, &sima->iuser); + else { + BKE_image_multiview_index(image, &sima->iuser); + } - if (ibuf) { - const int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(ibuf); - if (sima_flag & SI_SHOW_ZBUF && (ibuf->zbuf || ibuf->zbuf_float || (ibuf->channels == 1))) { - if (ibuf->zbuf) { - BLI_assert_msg(0, "Integer based depth buffers not supported"); - } - else if (ibuf->zbuf_float) { - *r_gpu_texture = GPU_texture_create_2d( - __func__, ibuf->x, ibuf->y, 0, GPU_R16F, ibuf->zbuf_float); - *r_owns_texture = true; - } - else if (ibuf->rect_float && ibuf->channels == 1) { - *r_gpu_texture = GPU_texture_create_2d( - __func__, ibuf->x, ibuf->y, 0, GPU_R16F, ibuf->rect_float); - *r_owns_texture = true; - } + if (ibuf == NULL) { + return; + } + + if (ibuf->rect == NULL && ibuf->rect_float == NULL) { + /* This codepath is only supposed to happen when drawing a lazily-allocatable render result. + * In all the other cases the `ED_space_image_acquire_buffer()` is expected to return NULL as + * an image buffer when it has no pixels. */ + + BLI_assert(image->type == IMA_TYPE_R_RESULT); + + float zero[4] = {0, 0, 0, 0}; + *r_gpu_texture = GPU_texture_create_2d(__func__, 1, 1, 0, GPU_RGBA16F, zero); + *r_owns_texture = true; + return; + } + + const int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(ibuf); + if (sima_flag & SI_SHOW_ZBUF && (ibuf->zbuf || ibuf->zbuf_float || (ibuf->channels == 1))) { + if (ibuf->zbuf) { + BLI_assert_msg(0, "Integer based depth buffers not supported"); } - else if (image->source == IMA_SRC_TILED) { - *r_gpu_texture = BKE_image_get_gpu_tiles(image, iuser, ibuf); - *r_tex_tile_data = BKE_image_get_gpu_tilemap(image, iuser, NULL); - *r_owns_texture = false; + else if (ibuf->zbuf_float) { + *r_gpu_texture = GPU_texture_create_2d( + __func__, ibuf->x, ibuf->y, 0, GPU_R16F, ibuf->zbuf_float); + *r_owns_texture = true; } - else { - *r_gpu_texture = BKE_image_get_gpu_texture(image, iuser, ibuf); - *r_owns_texture = false; + else if (ibuf->rect_float && ibuf->channels == 1) { + *r_gpu_texture = GPU_texture_create_2d( + __func__, ibuf->x, ibuf->y, 0, GPU_R16F, ibuf->rect_float); + *r_owns_texture = true; } } + else if (image->source == IMA_SRC_TILED) { + *r_gpu_texture = BKE_image_get_gpu_tiles(image, iuser, ibuf); + *r_tex_tile_data = BKE_image_get_gpu_tilemap(image, iuser, NULL); + *r_owns_texture = false; + } + else { + *r_gpu_texture = BKE_image_get_gpu_texture(image, iuser, ibuf); + *r_owns_texture = false; + } } static void space_node_gpu_texture_get(Image *image, diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c index 2a9080eb217..04d90919a20 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.c +++ b/source/blender/draw/engines/overlay/overlay_extra.c @@ -864,7 +864,6 @@ typedef union OVERLAY_CameraInstanceData { static void camera_view3d_reconstruction(OVERLAY_ExtraCallBuffers *cb, Scene *scene, View3D *v3d, - Object *camera_object, Object *ob, const float color[4]) { @@ -943,7 +942,7 @@ static void camera_view3d_reconstruction(OVERLAY_ExtraCallBuffers *cb, } if (is_select) { - DRW_select_load_id(camera_object->runtime.select_id | (track_index << 16)); + DRW_select_load_id(ob->runtime.select_id | (track_index << 16)); track_index++; } @@ -1251,7 +1250,7 @@ void OVERLAY_camera_cache_populate(OVERLAY_Data *vedata, Object *ob) /* Motion Tracking. */ if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) != 0) { - camera_view3d_reconstruction(cb, scene, v3d, camera_object, ob, color_p); + camera_view3d_reconstruction(cb, scene, v3d, ob, color_p); } /* Background images. */ diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h index 7dc468d1a73..db96d6a774f 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.h @@ -101,7 +101,7 @@ BLI_INLINE int mesh_render_mat_len_get(const Mesh *me) return MAX2(1, me->totcol); } -typedef struct MeshBufferCache { +typedef struct MeshBufferList { /* Every VBO below contains at least enough * data for every loops in the mesh (except fdots and skin roots). * For some VBOs, it extends to (in this exact order) : @@ -152,16 +152,91 @@ typedef struct MeshBufferCache { GPUIndexBuf *edituv_points; GPUIndexBuf *edituv_fdots; } ibo; - /* Index buffer per material. These are subranges of `ibo.tris` */ - GPUIndexBuf **tris_per_mat; -} MeshBufferCache; +} MeshBufferList; + +typedef struct MeshBatchList { + /* Surfaces / Render */ + GPUBatch *surface; + GPUBatch *surface_weights; + /* Edit mode */ + GPUBatch *edit_triangles; + GPUBatch *edit_vertices; + GPUBatch *edit_edges; + GPUBatch *edit_vnor; + GPUBatch *edit_lnor; + GPUBatch *edit_fdots; + GPUBatch *edit_mesh_analysis; + GPUBatch *edit_skin_roots; + /* Edit UVs */ + GPUBatch *edituv_faces_stretch_area; + GPUBatch *edituv_faces_stretch_angle; + GPUBatch *edituv_faces; + GPUBatch *edituv_edges; + GPUBatch *edituv_verts; + GPUBatch *edituv_fdots; + /* Edit selection */ + GPUBatch *edit_selection_verts; + GPUBatch *edit_selection_edges; + GPUBatch *edit_selection_faces; + GPUBatch *edit_selection_fdots; + /* Common display / Other */ + GPUBatch *all_verts; + GPUBatch *all_edges; + GPUBatch *loose_edges; + GPUBatch *edge_detection; + GPUBatch *wire_edges; /* Individual edges with face normals. */ + GPUBatch *wire_loops; /* Loops around faces. no edges between selected faces */ + GPUBatch *wire_loops_uvs; /* Same as wire_loops but only has uvs. */ + GPUBatch *sculpt_overlays; +} MeshBatchList; + +#define MBC_BATCH_LEN (sizeof(MeshBatchList) / sizeof(void *)) +#define MBC_VBO_LEN (sizeof(((MeshBufferList){0}).vbo) / sizeof(void *)) +#define MBC_IBO_LEN (sizeof(((MeshBufferList){0}).ibo) / sizeof(void *)) + +#define MBC_BATCH_INDEX(batch) (offsetof(MeshBatchList, batch) / sizeof(void *)) + +typedef enum DRWBatchFlag { + MBC_SURFACE = (1u << MBC_BATCH_INDEX(surface)), + MBC_SURFACE_WEIGHTS = (1u << MBC_BATCH_INDEX(surface_weights)), + MBC_EDIT_TRIANGLES = (1u << MBC_BATCH_INDEX(edit_triangles)), + MBC_EDIT_VERTICES = (1u << MBC_BATCH_INDEX(edit_vertices)), + MBC_EDIT_EDGES = (1u << MBC_BATCH_INDEX(edit_edges)), + MBC_EDIT_VNOR = (1u << MBC_BATCH_INDEX(edit_vnor)), + MBC_EDIT_LNOR = (1u << MBC_BATCH_INDEX(edit_lnor)), + MBC_EDIT_FACEDOTS = (1u << MBC_BATCH_INDEX(edit_fdots)), + MBC_EDIT_MESH_ANALYSIS = (1u << MBC_BATCH_INDEX(edit_mesh_analysis)), + MBC_SKIN_ROOTS = (1u << MBC_BATCH_INDEX(edit_skin_roots)), + MBC_EDITUV_FACES_STRETCH_AREA = (1u << MBC_BATCH_INDEX(edituv_faces_stretch_area)), + MBC_EDITUV_FACES_STRETCH_ANGLE = (1u << MBC_BATCH_INDEX(edituv_faces_stretch_angle)), + MBC_EDITUV_FACES = (1u << MBC_BATCH_INDEX(edituv_faces)), + MBC_EDITUV_EDGES = (1u << MBC_BATCH_INDEX(edituv_edges)), + MBC_EDITUV_VERTS = (1u << MBC_BATCH_INDEX(edituv_verts)), + MBC_EDITUV_FACEDOTS = (1u << MBC_BATCH_INDEX(edituv_fdots)), + MBC_EDIT_SELECTION_VERTS = (1u << MBC_BATCH_INDEX(edit_selection_verts)), + MBC_EDIT_SELECTION_EDGES = (1u << MBC_BATCH_INDEX(edit_selection_edges)), + MBC_EDIT_SELECTION_FACES = (1u << MBC_BATCH_INDEX(edit_selection_faces)), + MBC_EDIT_SELECTION_FACEDOTS = (1u << MBC_BATCH_INDEX(edit_selection_fdots)), + MBC_ALL_VERTS = (1u << MBC_BATCH_INDEX(all_verts)), + MBC_ALL_EDGES = (1u << MBC_BATCH_INDEX(all_edges)), + MBC_LOOSE_EDGES = (1u << MBC_BATCH_INDEX(loose_edges)), + MBC_EDGE_DETECTION = (1u << MBC_BATCH_INDEX(edge_detection)), + MBC_WIRE_EDGES = (1u << MBC_BATCH_INDEX(wire_edges)), + MBC_WIRE_LOOPS = (1u << MBC_BATCH_INDEX(wire_loops)), + MBC_WIRE_LOOPS_UVS = (1u << MBC_BATCH_INDEX(wire_loops_uvs)), + MBC_SCULPT_OVERLAYS = (1u << MBC_BATCH_INDEX(sculpt_overlays)), +} DRWBatchFlag; + +BLI_STATIC_ASSERT(MBC_BATCH_LEN < 32, "Number of batches exceeded the limit of bit fields"); /** * Data that are kept around between extractions to reduce rebuilding time. * * - Loose geometry. */ -typedef struct MeshBufferExtractionCache { +typedef struct MeshBufferCache { + MeshBufferList buff; + struct { int edge_len; int vert_len; @@ -174,7 +249,7 @@ typedef struct MeshBufferExtractionCache { int *mat_tri_len; int visible_tri_len; } poly_sorted; -} MeshBufferExtractionCache; +} MeshBufferCache; #define FOREACH_MESH_BUFFER_CACHE(batch_cache, mbc) \ for (MeshBufferCache *mbc = &batch_cache->final; \ @@ -186,50 +261,15 @@ typedef struct MeshBufferExtractionCache { typedef struct MeshBatchCache { MeshBufferCache final, cage, uv_cage; - MeshBufferExtractionCache final_extraction_cache; - MeshBufferExtractionCache cage_extraction_cache; - MeshBufferExtractionCache uv_cage_extraction_cache; + MeshBatchList batch; - struct { - /* Surfaces / Render */ - GPUBatch *surface; - GPUBatch *surface_weights; - /* Edit mode */ - GPUBatch *edit_triangles; - GPUBatch *edit_vertices; - GPUBatch *edit_edges; - GPUBatch *edit_vnor; - GPUBatch *edit_lnor; - GPUBatch *edit_fdots; - GPUBatch *edit_mesh_analysis; - GPUBatch *edit_skin_roots; - /* Edit UVs */ - GPUBatch *edituv_faces_stretch_area; - GPUBatch *edituv_faces_stretch_angle; - GPUBatch *edituv_faces; - GPUBatch *edituv_edges; - GPUBatch *edituv_verts; - GPUBatch *edituv_fdots; - /* Edit selection */ - GPUBatch *edit_selection_verts; - GPUBatch *edit_selection_edges; - GPUBatch *edit_selection_faces; - GPUBatch *edit_selection_fdots; - /* Common display / Other */ - GPUBatch *all_verts; - GPUBatch *all_edges; - GPUBatch *loose_edges; - GPUBatch *edge_detection; - GPUBatch *wire_edges; /* Individual edges with face normals. */ - GPUBatch *wire_loops; /* Loops around faces. no edges between selected faces */ - GPUBatch *wire_loops_uvs; /* Same as wire_loops but only has uvs. */ - GPUBatch *sculpt_overlays; - } batch; + /* Index buffer per material. These are subranges of `ibo.tris` */ + GPUIndexBuf **tris_per_mat; GPUBatch **surface_per_mat; - uint32_t batch_requested; /* DRWBatchFlag */ - uint32_t batch_ready; /* DRWBatchFlag */ + DRWBatchFlag batch_requested; /* DRWBatchFlag */ + DRWBatchFlag batch_ready; /* DRWBatchFlag */ /* settings to determine if cache is invalid */ int edge_len; @@ -259,55 +299,13 @@ typedef struct MeshBatchCache { bool no_loose_wire; } MeshBatchCache; -#define MBC_BATCH_LEN (sizeof(((MeshBatchCache){0}).batch) / sizeof(void *)) -#define MBC_VBO_LEN (sizeof(((MeshBufferCache){0}).vbo) / sizeof(void *)) -#define MBC_IBO_LEN (sizeof(((MeshBufferCache){0}).ibo) / sizeof(void *)) - -#define MBC_BATCH_INDEX(batch_name) \ - ((offsetof(MeshBatchCache, batch_name) - offsetof(MeshBatchCache, batch)) / sizeof(void *)) - -typedef enum DRWBatchFlag { - MBC_SURFACE = (1u << MBC_BATCH_INDEX(batch.surface)), - MBC_SURFACE_WEIGHTS = (1u << MBC_BATCH_INDEX(batch.surface_weights)), - MBC_EDIT_TRIANGLES = (1u << MBC_BATCH_INDEX(batch.edit_triangles)), - MBC_EDIT_VERTICES = (1u << MBC_BATCH_INDEX(batch.edit_vertices)), - MBC_EDIT_EDGES = (1u << MBC_BATCH_INDEX(batch.edit_edges)), - MBC_EDIT_VNOR = (1u << MBC_BATCH_INDEX(batch.edit_vnor)), - MBC_EDIT_LNOR = (1u << MBC_BATCH_INDEX(batch.edit_lnor)), - MBC_EDIT_FACEDOTS = (1u << MBC_BATCH_INDEX(batch.edit_fdots)), - MBC_EDIT_MESH_ANALYSIS = (1u << MBC_BATCH_INDEX(batch.edit_mesh_analysis)), - MBC_SKIN_ROOTS = (1u << MBC_BATCH_INDEX(batch.edit_skin_roots)), - MBC_EDITUV_FACES_STRETCH_AREA = (1u << MBC_BATCH_INDEX(batch.edituv_faces_stretch_area)), - MBC_EDITUV_FACES_STRETCH_ANGLE = (1u << MBC_BATCH_INDEX(batch.edituv_faces_stretch_angle)), - MBC_EDITUV_FACES = (1u << MBC_BATCH_INDEX(batch.edituv_faces)), - MBC_EDITUV_EDGES = (1u << MBC_BATCH_INDEX(batch.edituv_edges)), - MBC_EDITUV_VERTS = (1u << MBC_BATCH_INDEX(batch.edituv_verts)), - MBC_EDITUV_FACEDOTS = (1u << MBC_BATCH_INDEX(batch.edituv_fdots)), - MBC_EDIT_SELECTION_VERTS = (1u << MBC_BATCH_INDEX(batch.edit_selection_verts)), - MBC_EDIT_SELECTION_EDGES = (1u << MBC_BATCH_INDEX(batch.edit_selection_edges)), - MBC_EDIT_SELECTION_FACES = (1u << MBC_BATCH_INDEX(batch.edit_selection_faces)), - MBC_EDIT_SELECTION_FACEDOTS = (1u << MBC_BATCH_INDEX(batch.edit_selection_fdots)), - MBC_ALL_VERTS = (1u << MBC_BATCH_INDEX(batch.all_verts)), - MBC_ALL_EDGES = (1u << MBC_BATCH_INDEX(batch.all_edges)), - MBC_LOOSE_EDGES = (1u << MBC_BATCH_INDEX(batch.loose_edges)), - MBC_EDGE_DETECTION = (1u << MBC_BATCH_INDEX(batch.edge_detection)), - MBC_WIRE_EDGES = (1u << MBC_BATCH_INDEX(batch.wire_edges)), - MBC_WIRE_LOOPS = (1u << MBC_BATCH_INDEX(batch.wire_loops)), - MBC_WIRE_LOOPS_UVS = (1u << MBC_BATCH_INDEX(batch.wire_loops_uvs)), - MBC_SCULPT_OVERLAYS = (1u << MBC_BATCH_INDEX(batch.sculpt_overlays)), -} DRWBatchFlag; - -BLI_STATIC_ASSERT(MBC_BATCH_INDEX(surface_per_mat) < 32, - "Number of batches exceeded the limit of bit fields"); - #define MBC_EDITUV \ (MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | \ MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS | MBC_WIRE_LOOPS_UVS) void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, - MeshBatchCache *cache, - MeshBufferCache *mbc, - MeshBufferExtractionCache *extraction_cache, + MeshBatchCache *mbc, + MeshBufferCache *extraction_cache, Mesh *me, const bool is_editmode, const bool is_paint_mode, diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc index 1bc2b8a9def..06c449fe590 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc @@ -162,7 +162,7 @@ struct ExtractTaskData { const MeshRenderData *mr = nullptr; MeshBatchCache *cache = nullptr; ExtractorRunDatas *extractors = nullptr; - MeshBufferCache *mbc = nullptr; + MeshBufferList *mbuflist = nullptr; eMRIterType iter_type; bool use_threading = false; @@ -170,9 +170,13 @@ struct ExtractTaskData { ExtractTaskData(const MeshRenderData *mr, struct MeshBatchCache *cache, ExtractorRunDatas *extractors, - MeshBufferCache *mbc, + MeshBufferList *mbuflist, const bool use_threading) - : mr(mr), cache(cache), extractors(extractors), mbc(mbc), use_threading(use_threading) + : mr(mr), + cache(cache), + extractors(extractors), + mbuflist(mbuflist), + use_threading(use_threading) { iter_type = extractors->iter_types(); }; @@ -204,13 +208,13 @@ static void extract_task_data_free(void *data) BLI_INLINE void extract_init(const MeshRenderData *mr, struct MeshBatchCache *cache, ExtractorRunDatas &extractors, - MeshBufferCache *mbc, + MeshBufferList *mbuflist, void *data_stack) { uint32_t data_offset = 0; for (ExtractorRunData &run_data : extractors) { const MeshExtract *extractor = run_data.extractor; - run_data.buffer = mesh_extract_buffer_get(extractor, mbc); + run_data.buffer = mesh_extract_buffer_get(extractor, mbuflist); run_data.data_offset = data_offset; extractor->init(mr, cache, run_data.buffer, POINTER_OFFSET(data_stack, data_offset)); data_offset += (uint32_t)extractor->data_size; @@ -445,7 +449,7 @@ static void extract_task_range_run(void *__restrict taskdata) settings.func_reduce = extract_task_reduce; settings.min_iter_per_thread = MIN_RANGE_LEN; - extract_init(data->mr, data->cache, *data->extractors, data->mbc, userdata_chunk); + extract_init(data->mr, data->cache, *data->extractors, data->mbuflist, userdata_chunk); if (iter_type & MR_ITER_LOOPTRI) { extract_task_range_run_iter(data->mr, data->extractors, MR_ITER_LOOPTRI, is_mesh, &settings); @@ -474,10 +478,10 @@ static struct TaskNode *extract_task_node_create(struct TaskGraph *task_graph, const MeshRenderData *mr, MeshBatchCache *cache, ExtractorRunDatas *extractors, - MeshBufferCache *mbc, + MeshBufferList *mbuflist, const bool use_threading) { - ExtractTaskData *taskdata = new ExtractTaskData(mr, cache, extractors, mbc, use_threading); + ExtractTaskData *taskdata = new ExtractTaskData(mr, cache, extractors, mbuflist, use_threading); struct TaskNode *task_node = BLI_task_graph_node_create( task_graph, extract_task_range_run, @@ -493,12 +497,12 @@ static struct TaskNode *extract_task_node_create(struct TaskGraph *task_graph, * \{ */ struct MeshRenderDataUpdateTaskData { MeshRenderData *mr = nullptr; - MeshBufferExtractionCache *cache = nullptr; + MeshBufferCache *cache = nullptr; eMRIterType iter_type; eMRDataType data_flag; MeshRenderDataUpdateTaskData(MeshRenderData *mr, - MeshBufferExtractionCache *cache, + MeshBufferCache *cache, eMRIterType iter_type, eMRDataType data_flag) : mr(mr), cache(cache), iter_type(iter_type), data_flag(data_flag) @@ -538,7 +542,7 @@ static void mesh_extract_render_data_node_exec(void *__restrict task_data) static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *task_graph, MeshRenderData *mr, - MeshBufferExtractionCache *cache, + MeshBufferCache *cache, const eMRIterType iter_type, const eMRDataType data_flag) { @@ -562,7 +566,6 @@ static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *t static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, MeshBatchCache *cache, MeshBufferCache *mbc, - MeshBufferExtractionCache *extraction_cache, Mesh *me, const bool is_editmode, @@ -613,9 +616,11 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, /* Create an array containing all the extractors that needs to be executed. */ ExtractorRunDatas extractors; + MeshBufferList *mbuflist = &mbc->buff; + #define EXTRACT_ADD_REQUESTED(type, name) \ do { \ - if (DRW_##type##_requested(mbc->type.name)) { \ + if (DRW_##type##_requested(mbuflist->type.name)) { \ const MeshExtract *extractor = mesh_extract_override_get( \ &extract_##name, do_hq_normals, override_single_mat); \ extractors.append(extractor); \ @@ -647,19 +652,19 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, EXTRACT_ADD_REQUESTED(vbo, skin_roots); EXTRACT_ADD_REQUESTED(ibo, tris); - if (DRW_ibo_requested(mbc->ibo.lines_loose)) { + if (DRW_ibo_requested(mbuflist->ibo.lines_loose)) { /* `ibo.lines_loose` require the `ibo.lines` buffer. */ - if (mbc->ibo.lines == nullptr) { - DRW_ibo_request(nullptr, &mbc->ibo.lines); + if (mbuflist->ibo.lines == nullptr) { + DRW_ibo_request(nullptr, &mbuflist->ibo.lines); } - const MeshExtract *extractor = DRW_ibo_requested(mbc->ibo.lines) ? + const MeshExtract *extractor = DRW_ibo_requested(mbuflist->ibo.lines) ? &extract_lines_with_lines_loose : &extract_lines_loose_only; extractors.append(extractor); } - else if (DRW_ibo_requested(mbc->ibo.lines)) { + else if (DRW_ibo_requested(mbuflist->ibo.lines)) { const MeshExtract *extractor; - if (mbc->ibo.lines_loose != nullptr) { + if (mbuflist->ibo.lines_loose != nullptr) { /* Update `ibo.lines_loose` as it depends on `ibo.lines`. */ extractor = &extract_lines_with_lines_loose; } @@ -701,7 +706,7 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, eMRDataType data_flag = extractors.data_types(); struct TaskNode *task_node_mesh_render_data = mesh_extract_render_data_node_create( - task_graph, mr, extraction_cache, iter_type, data_flag); + task_graph, mr, mbc, iter_type, data_flag); /* Simple heuristic. */ const bool use_thread = (mr->loop_len + mr->loop_loose_len) > MIN_RANGE_LEN; @@ -714,7 +719,7 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, ExtractorRunDatas *single_threaded_extractors = new ExtractorRunDatas(); single_threaded_extractors->append(extractor); struct TaskNode *task_node = extract_task_node_create( - task_graph, mr, cache, single_threaded_extractors, mbc, false); + task_graph, mr, cache, single_threaded_extractors, mbuflist, false); BLI_task_graph_edge_create(task_node_mesh_render_data, task_node); } @@ -725,7 +730,7 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, extractors.filter_threaded_extractors_into(*multi_threaded_extractors); if (!multi_threaded_extractors->is_empty()) { struct TaskNode *task_node = extract_task_node_create( - task_graph, mr, cache, multi_threaded_extractors, mbc, true); + task_graph, mr, cache, multi_threaded_extractors, mbuflist, true); BLI_task_graph_edge_create(task_node_mesh_render_data, task_node); } @@ -738,7 +743,7 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, /* Run all requests on the same thread. */ ExtractorRunDatas *extractors_copy = new ExtractorRunDatas(extractors); struct TaskNode *task_node = extract_task_node_create( - task_graph, mr, cache, extractors_copy, mbc, false); + task_graph, mr, cache, extractors_copy, mbuflist, false); BLI_task_graph_edge_create(task_node_mesh_render_data, task_node); } @@ -776,7 +781,6 @@ extern "C" { void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, MeshBatchCache *cache, MeshBufferCache *mbc, - MeshBufferExtractionCache *extraction_cache, Mesh *me, const bool is_editmode, @@ -793,7 +797,6 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, blender::draw::mesh_buffer_cache_create_requested(task_graph, cache, mbc, - extraction_cache, me, is_editmode, is_paint_mode, diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c index 27fd6ca9134..abfbeabef6b 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c @@ -45,17 +45,15 @@ * \{ */ static void mesh_render_data_lverts_bm(const MeshRenderData *mr, - MeshBufferExtractionCache *cache, + MeshBufferCache *cache, BMesh *bm); static void mesh_render_data_ledges_bm(const MeshRenderData *mr, - MeshBufferExtractionCache *cache, + MeshBufferCache *cache, BMesh *bm); -static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, - MeshBufferExtractionCache *cache); -static void mesh_render_data_loose_geom_build(const MeshRenderData *mr, - MeshBufferExtractionCache *cache); +static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBufferCache *cache); +static void mesh_render_data_loose_geom_build(const MeshRenderData *mr, MeshBufferCache *cache); -static void mesh_render_data_loose_geom_load(MeshRenderData *mr, MeshBufferExtractionCache *cache) +static void mesh_render_data_loose_geom_load(MeshRenderData *mr, MeshBufferCache *cache) { mr->ledges = cache->loose_geom.edges; mr->lverts = cache->loose_geom.verts; @@ -65,8 +63,7 @@ static void mesh_render_data_loose_geom_load(MeshRenderData *mr, MeshBufferExtra mr->loop_loose_len = mr->vert_loose_len + (mr->edge_loose_len * 2); } -static void mesh_render_data_loose_geom_ensure(const MeshRenderData *mr, - MeshBufferExtractionCache *cache) +static void mesh_render_data_loose_geom_ensure(const MeshRenderData *mr, MeshBufferCache *cache) { /* Early exit: Are loose geometry already available. * Only checking for loose verts as loose edges and verts are calculated at the same time. */ @@ -76,8 +73,7 @@ static void mesh_render_data_loose_geom_ensure(const MeshRenderData *mr, mesh_render_data_loose_geom_build(mr, cache); } -static void mesh_render_data_loose_geom_build(const MeshRenderData *mr, - MeshBufferExtractionCache *cache) +static void mesh_render_data_loose_geom_build(const MeshRenderData *mr, MeshBufferCache *cache) { cache->loose_geom.vert_len = 0; cache->loose_geom.edge_len = 0; @@ -94,8 +90,7 @@ static void mesh_render_data_loose_geom_build(const MeshRenderData *mr, } } -static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, - MeshBufferExtractionCache *cache) +static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBufferCache *cache) { BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__); @@ -128,9 +123,7 @@ static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MEM_freeN(lvert_map); } -static void mesh_render_data_lverts_bm(const MeshRenderData *mr, - MeshBufferExtractionCache *cache, - BMesh *bm) +static void mesh_render_data_lverts_bm(const MeshRenderData *mr, MeshBufferCache *cache, BMesh *bm) { int elem_id; BMIter iter; @@ -147,9 +140,7 @@ static void mesh_render_data_lverts_bm(const MeshRenderData *mr, } } -static void mesh_render_data_ledges_bm(const MeshRenderData *mr, - MeshBufferExtractionCache *cache, - BMesh *bm) +static void mesh_render_data_ledges_bm(const MeshRenderData *mr, MeshBufferCache *cache, BMesh *bm) { int elem_id; BMIter iter; @@ -167,7 +158,7 @@ static void mesh_render_data_ledges_bm(const MeshRenderData *mr, } void mesh_render_data_update_loose_geom(MeshRenderData *mr, - MeshBufferExtractionCache *cache, + MeshBufferCache *cache, const eMRIterType iter_type, const eMRDataType data_flag) { @@ -185,16 +176,13 @@ void mesh_render_data_update_loose_geom(MeshRenderData *mr, * Contains polygon indices sorted based on their material. * * \{ */ -static void mesh_render_data_polys_sorted_load(MeshRenderData *mr, - const MeshBufferExtractionCache *cache); -static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, - MeshBufferExtractionCache *cache); -static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, - MeshBufferExtractionCache *cache); +static void mesh_render_data_polys_sorted_load(MeshRenderData *mr, const MeshBufferCache *cache); +static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, MeshBufferCache *cache); +static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCache *cache); static int *mesh_render_data_mat_tri_len_build(MeshRenderData *mr); void mesh_render_data_update_polys_sorted(MeshRenderData *mr, - MeshBufferExtractionCache *cache, + MeshBufferCache *cache, const eMRDataType data_flag) { if (data_flag & MR_DATA_POLYS_SORTED) { @@ -203,16 +191,14 @@ void mesh_render_data_update_polys_sorted(MeshRenderData *mr, } } -static void mesh_render_data_polys_sorted_load(MeshRenderData *mr, - const MeshBufferExtractionCache *cache) +static void mesh_render_data_polys_sorted_load(MeshRenderData *mr, const MeshBufferCache *cache) { mr->poly_sorted.tri_first_index = cache->poly_sorted.tri_first_index; mr->poly_sorted.mat_tri_len = cache->poly_sorted.mat_tri_len; mr->poly_sorted.visible_tri_len = cache->poly_sorted.visible_tri_len; } -static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, - MeshBufferExtractionCache *cache) +static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, MeshBufferCache *cache) { if (cache->poly_sorted.tri_first_index) { return; @@ -220,8 +206,7 @@ static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, mesh_render_data_polys_sorted_build(mr, cache); } -static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, - MeshBufferExtractionCache *cache) +static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCache *cache) { int *tri_first_index = MEM_mallocN(sizeof(*tri_first_index) * mr->poly_len, __func__); int *mat_tri_len = mesh_render_data_mat_tri_len_build(mr); @@ -584,7 +569,7 @@ void mesh_render_data_free(MeshRenderData *mr) MEM_SAFE_FREE(mr->mlooptri); MEM_SAFE_FREE(mr->loop_normals); - /* Loose geometry are owned by #MeshBufferExtractionCache. */ + /* Loose geometry are owned by #MeshBufferCache. */ mr->ledges = NULL; mr->lverts = NULL; diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 52b76733b78..18664498d00 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -79,39 +79,42 @@ /* clang-format off */ -#define _BUFFER_INDEX(buff_name) ((offsetof(MeshBufferCache, buff_name) - offsetof(MeshBufferCache, vbo)) / sizeof(void *)) - -#define _MDEPS_CREATE1(b) (1u << MBC_BATCH_INDEX(b)) -#define _MDEPS_CREATE2(b1, b2) _MDEPS_CREATE1(b1) | _MDEPS_CREATE1(b2) -#define _MDEPS_CREATE3(b1, b2, b3) _MDEPS_CREATE2(b1, b2) | _MDEPS_CREATE1(b3) -#define _MDEPS_CREATE4(b1, b2, b3, b4) _MDEPS_CREATE3(b1, b2, b3) | _MDEPS_CREATE1(b4) -#define _MDEPS_CREATE5(b1, b2, b3, b4, b5) _MDEPS_CREATE4(b1, b2, b3, b4) | _MDEPS_CREATE1(b5) -#define _MDEPS_CREATE6(b1, b2, b3, b4, b5, b6) _MDEPS_CREATE5(b1, b2, b3, b4, b5) | _MDEPS_CREATE1(b6) -#define _MDEPS_CREATE7(b1, b2, b3, b4, b5, b6, b7) _MDEPS_CREATE6(b1, b2, b3, b4, b5, b6) | _MDEPS_CREATE1(b7) -#define _MDEPS_CREATE8(b1, b2, b3, b4, b5, b6, b7, b8) _MDEPS_CREATE7(b1, b2, b3, b4, b5, b6, b7) | _MDEPS_CREATE1(b8) -#define _MDEPS_CREATE9(b1, b2, b3, b4, b5, b6, b7, b8, b9) _MDEPS_CREATE8(b1, b2, b3, b4, b5, b6, b7, b8) | _MDEPS_CREATE1(b9) -#define _MDEPS_CREATE10(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10) _MDEPS_CREATE9(b1, b2, b3, b4, b5, b6, b7, b8, b9) | _MDEPS_CREATE1(b10) -#define _MDEPS_CREATE19(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19) _MDEPS_CREATE10(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10) | _MDEPS_CREATE9(b11, b12, b13, b14, b15, b16, b17, b18, b19) - -#define MDEPS_CREATE(buff_name, ...) [_BUFFER_INDEX(buff_name)] = VA_NARGS_CALL_OVERLOAD(_MDEPS_CREATE, __VA_ARGS__) - -#define _MDEPS_CREATE_MAP1(a) g_buffer_deps[_BUFFER_INDEX(a)] -#define _MDEPS_CREATE_MAP2(a, b) _MDEPS_CREATE_MAP1(a) | _MDEPS_CREATE_MAP1(b) -#define _MDEPS_CREATE_MAP3(a, b, c) _MDEPS_CREATE_MAP2(a, b) | _MDEPS_CREATE_MAP1(c) -#define _MDEPS_CREATE_MAP4(a, b, c, d) _MDEPS_CREATE_MAP3(a, b, c) | _MDEPS_CREATE_MAP1(d) -#define _MDEPS_CREATE_MAP5(a, b, c, d, e) _MDEPS_CREATE_MAP4(a, b, c, d) | _MDEPS_CREATE_MAP1(e) -#define _MDEPS_CREATE_MAP6(a, b, c, d, e, f) _MDEPS_CREATE_MAP5(a, b, c, d, e) | _MDEPS_CREATE_MAP1(f) -#define _MDEPS_CREATE_MAP7(a, b, c, d, e, f, g) _MDEPS_CREATE_MAP6(a, b, c, d, e, f) | _MDEPS_CREATE_MAP1(g) -#define _MDEPS_CREATE_MAP8(a, b, c, d, e, f, g, h) _MDEPS_CREATE_MAP7(a, b, c, d, e, f, g) | _MDEPS_CREATE_MAP1(h) -#define _MDEPS_CREATE_MAP9(a, b, c, d, e, f, g, h, i) _MDEPS_CREATE_MAP8(a, b, c, d, e, f, g, h) | _MDEPS_CREATE_MAP1(i) -#define _MDEPS_CREATE_MAP10(a, b, c, d, e, f, g, h, i, j) _MDEPS_CREATE_MAP9(a, b, c, d, e, f, g, h, i) | _MDEPS_CREATE_MAP1(j) - -#define MDEPS_CREATE_MAP(...) VA_NARGS_CALL_OVERLOAD(_MDEPS_CREATE_MAP, __VA_ARGS__) +#define BUFFER_INDEX(buff_name) ((offsetof(MeshBufferList, buff_name) - offsetof(MeshBufferList, vbo)) / sizeof(void *)) +#define BUFFER_LEN (sizeof(MeshBufferList) / sizeof(void *)) + +#define _BATCH_FLAG1(b) (1u << MBC_BATCH_INDEX(b)) +#define _BATCH_FLAG2(b1, b2) _BATCH_FLAG1(b1) | _BATCH_FLAG1(b2) +#define _BATCH_FLAG3(b1, b2, b3) _BATCH_FLAG2(b1, b2) | _BATCH_FLAG1(b3) +#define _BATCH_FLAG4(b1, b2, b3, b4) _BATCH_FLAG3(b1, b2, b3) | _BATCH_FLAG1(b4) +#define _BATCH_FLAG5(b1, b2, b3, b4, b5) _BATCH_FLAG4(b1, b2, b3, b4) | _BATCH_FLAG1(b5) +#define _BATCH_FLAG6(b1, b2, b3, b4, b5, b6) _BATCH_FLAG5(b1, b2, b3, b4, b5) | _BATCH_FLAG1(b6) +#define _BATCH_FLAG7(b1, b2, b3, b4, b5, b6, b7) _BATCH_FLAG6(b1, b2, b3, b4, b5, b6) | _BATCH_FLAG1(b7) +#define _BATCH_FLAG8(b1, b2, b3, b4, b5, b6, b7, b8) _BATCH_FLAG7(b1, b2, b3, b4, b5, b6, b7) | _BATCH_FLAG1(b8) +#define _BATCH_FLAG9(b1, b2, b3, b4, b5, b6, b7, b8, b9) _BATCH_FLAG8(b1, b2, b3, b4, b5, b6, b7, b8) | _BATCH_FLAG1(b9) +#define _BATCH_FLAG10(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10) _BATCH_FLAG9(b1, b2, b3, b4, b5, b6, b7, b8, b9) | _BATCH_FLAG1(b10) +#define _BATCH_FLAG18(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18) _BATCH_FLAG10(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10) | _BATCH_FLAG8(b11, b12, b13, b14, b15, b16, b17, b18) + +#define BATCH_FLAG(...) VA_NARGS_CALL_OVERLOAD(_BATCH_FLAG, __VA_ARGS__) + +#define _BATCH_MAP1(a) g_buffer_deps[BUFFER_INDEX(a)] +#define _BATCH_MAP2(a, b) _BATCH_MAP1(a) | _BATCH_MAP1(b) +#define _BATCH_MAP3(a, b, c) _BATCH_MAP2(a, b) | _BATCH_MAP1(c) +#define _BATCH_MAP4(a, b, c, d) _BATCH_MAP3(a, b, c) | _BATCH_MAP1(d) +#define _BATCH_MAP5(a, b, c, d, e) _BATCH_MAP4(a, b, c, d) | _BATCH_MAP1(e) +#define _BATCH_MAP6(a, b, c, d, e, f) _BATCH_MAP5(a, b, c, d, e) | _BATCH_MAP1(f) +#define _BATCH_MAP7(a, b, c, d, e, f, g) _BATCH_MAP6(a, b, c, d, e, f) | _BATCH_MAP1(g) +#define _BATCH_MAP8(a, b, c, d, e, f, g, h) _BATCH_MAP7(a, b, c, d, e, f, g) | _BATCH_MAP1(h) +#define _BATCH_MAP9(a, b, c, d, e, f, g, h, i) _BATCH_MAP8(a, b, c, d, e, f, g, h) | _BATCH_MAP1(i) +#define _BATCH_MAP10(a, b, c, d, e, f, g, h, i, j) _BATCH_MAP9(a, b, c, d, e, f, g, h, i) | _BATCH_MAP1(j) + +#define BATCH_MAP(...) VA_NARGS_CALL_OVERLOAD(_BATCH_MAP, __VA_ARGS__) #ifndef NDEBUG -# define _MDEPS_ASSERT2(b, name) \ - g_buffer_deps_d[_BUFFER_INDEX(name)] |= _MDEPS_CREATE1(b); \ - BLI_assert(g_buffer_deps[_BUFFER_INDEX(name)] & _MDEPS_CREATE1(b)) +# define MDEPS_ASSERT_INDEX(buffer_index, batch_flag) \ + g_buffer_deps_d[buffer_index] |= batch_flag; \ + BLI_assert(g_buffer_deps[buffer_index] & batch_flag) + +# define _MDEPS_ASSERT2(b, n1) MDEPS_ASSERT_INDEX(BUFFER_INDEX(n1), b) # define _MDEPS_ASSERT3(b, n1, n2) _MDEPS_ASSERT2(b, n1); _MDEPS_ASSERT2(b, n2) # define _MDEPS_ASSERT4(b, n1, n2, n3) _MDEPS_ASSERT3(b, n1, n2); _MDEPS_ASSERT2(b, n3) # define _MDEPS_ASSERT5(b, n1, n2, n3, n4) _MDEPS_ASSERT4(b, n1, n2, n3); _MDEPS_ASSERT2(b, n4) @@ -119,99 +122,97 @@ # define _MDEPS_ASSERT7(b, n1, n2, n3, n4, n5, n6) _MDEPS_ASSERT6(b, n1, n2, n3, n4, n5); _MDEPS_ASSERT2(b, n6) # define _MDEPS_ASSERT8(b, n1, n2, n3, n4, n5, n6, n7) _MDEPS_ASSERT7(b, n1, n2, n3, n4, n5, n6); _MDEPS_ASSERT2(b, n7) -# define MDEPS_ASSERT(...) VA_NARGS_CALL_OVERLOAD(_MDEPS_ASSERT, __VA_ARGS__) -# define MDEPS_ASSERT_MAP(name) BLI_assert(g_buffer_deps_d[_BUFFER_INDEX(name)] == g_buffer_deps[_BUFFER_INDEX(name)]) +# define MDEPS_ASSERT_FLAG(...) VA_NARGS_CALL_OVERLOAD(_MDEPS_ASSERT, __VA_ARGS__) +# define MDEPS_ASSERT(batch_name, ...) MDEPS_ASSERT_FLAG(BATCH_FLAG(batch_name), __VA_ARGS__) +# define MDEPS_ASSERT_MAP_INDEX(buff_index) BLI_assert(g_buffer_deps_d[buff_index] == g_buffer_deps[buff_index]) +# define MDEPS_ASSERT_MAP(buff_name) MDEPS_ASSERT_MAP_INDEX(BUFFER_INDEX(buff_name)) #else -# define MDEPS_ASSERT(...) -# define MDEPS_ASSERT_MAP(name) +# define MDEPS_ASSERT_INDEX(buffer_index, batch_flag) +# define MDEPS_ASSERT_FLAG(...) +# define MDEPS_ASSERT(batch_name, ...) +# define MDEPS_ASSERT_MAP_INDEX(buff_index) +# define MDEPS_ASSERT_MAP(buff_name) #endif /* clang-format on */ +#define TRIS_PER_MAT_INDEX BUFFER_LEN +#define SURFACE_PER_MAT_FLAG (1u << MBC_BATCH_LEN) + static const DRWBatchFlag g_buffer_deps[] = { - MDEPS_CREATE(vbo.pos_nor, - batch.surface, - batch.surface_weights, - batch.edit_triangles, - batch.edit_vertices, - batch.edit_edges, - batch.edit_vnor, - batch.edit_lnor, - batch.edit_mesh_analysis, - batch.edit_selection_verts, - batch.edit_selection_edges, - batch.edit_selection_faces, - batch.all_verts, - batch.all_edges, - batch.loose_edges, - batch.edge_detection, - batch.wire_edges, - batch.wire_loops, - batch.sculpt_overlays, - surface_per_mat), - MDEPS_CREATE(vbo.lnor, batch.surface, batch.edit_lnor, batch.wire_loops, surface_per_mat), - MDEPS_CREATE(vbo.edge_fac, batch.wire_edges), - MDEPS_CREATE(vbo.weights, batch.surface_weights), - MDEPS_CREATE(vbo.uv, - batch.surface, - batch.edituv_faces_stretch_area, - batch.edituv_faces_stretch_angle, - batch.edituv_faces, - batch.edituv_edges, - batch.edituv_verts, - batch.wire_loops_uvs, - surface_per_mat), - MDEPS_CREATE(vbo.tan, surface_per_mat), - MDEPS_CREATE(vbo.vcol, batch.surface, surface_per_mat), - MDEPS_CREATE(vbo.sculpt_data, batch.sculpt_overlays), - MDEPS_CREATE(vbo.orco, surface_per_mat), - MDEPS_CREATE(vbo.edit_data, batch.edit_triangles, batch.edit_edges, batch.edit_vertices), - MDEPS_CREATE(vbo.edituv_data, - batch.edituv_faces, - batch.edituv_faces_stretch_area, - batch.edituv_faces_stretch_angle, - batch.edituv_edges, - batch.edituv_verts), - MDEPS_CREATE(vbo.edituv_stretch_area, batch.edituv_faces_stretch_area), - MDEPS_CREATE(vbo.edituv_stretch_angle, batch.edituv_faces_stretch_angle), - MDEPS_CREATE(vbo.mesh_analysis, batch.edit_mesh_analysis), - MDEPS_CREATE(vbo.fdots_pos, batch.edit_fdots, batch.edit_selection_fdots), - MDEPS_CREATE(vbo.fdots_nor, batch.edit_fdots), - MDEPS_CREATE(vbo.fdots_uv, batch.edituv_fdots), - MDEPS_CREATE(vbo.fdots_edituv_data, batch.edituv_fdots), - MDEPS_CREATE(vbo.skin_roots, batch.edit_skin_roots), - MDEPS_CREATE(vbo.vert_idx, batch.edit_selection_verts), - MDEPS_CREATE(vbo.edge_idx, batch.edit_selection_edges), - MDEPS_CREATE(vbo.poly_idx, batch.edit_selection_faces), - MDEPS_CREATE(vbo.fdot_idx, batch.edit_selection_fdots), - - MDEPS_CREATE(ibo.tris, - batch.surface, - batch.surface_weights, - batch.edit_triangles, - batch.edit_lnor, - batch.edit_mesh_analysis, - batch.edit_selection_faces, - batch.sculpt_overlays), - MDEPS_CREATE(ibo.lines, - batch.edit_edges, - batch.edit_selection_edges, - batch.all_edges, - batch.wire_edges), - MDEPS_CREATE(ibo.lines_loose, batch.loose_edges), - MDEPS_CREATE(ibo.points, batch.edit_vnor, batch.edit_vertices, batch.edit_selection_verts), - MDEPS_CREATE(ibo.fdots, batch.edit_fdots, batch.edit_selection_fdots), - MDEPS_CREATE(ibo.lines_paint_mask, batch.wire_loops), - MDEPS_CREATE(ibo.lines_adjacency, batch.edge_detection), - MDEPS_CREATE(ibo.edituv_tris, - batch.edituv_faces, - batch.edituv_faces_stretch_area, - batch.edituv_faces_stretch_angle), - MDEPS_CREATE(ibo.edituv_lines, batch.edituv_edges, batch.wire_loops_uvs), - MDEPS_CREATE(ibo.edituv_points, batch.edituv_verts), - MDEPS_CREATE(ibo.edituv_fdots, batch.edituv_fdots), - - MDEPS_CREATE(tris_per_mat, surface_per_mat), + [BUFFER_INDEX(vbo.pos_nor)] = BATCH_FLAG(surface, + surface_weights, + edit_triangles, + edit_vertices, + edit_edges, + edit_vnor, + edit_lnor, + edit_mesh_analysis, + edit_selection_verts, + edit_selection_edges, + edit_selection_faces, + all_verts, + all_edges, + loose_edges, + edge_detection, + wire_edges, + wire_loops, + sculpt_overlays) | + SURFACE_PER_MAT_FLAG, + [BUFFER_INDEX(vbo.lnor)] = BATCH_FLAG(surface, edit_lnor, wire_loops) | SURFACE_PER_MAT_FLAG, + [BUFFER_INDEX(vbo.edge_fac)] = BATCH_FLAG(wire_edges), + [BUFFER_INDEX(vbo.weights)] = BATCH_FLAG(surface_weights), + [BUFFER_INDEX(vbo.uv)] = BATCH_FLAG(surface, + edituv_faces_stretch_area, + edituv_faces_stretch_angle, + edituv_faces, + edituv_edges, + edituv_verts, + wire_loops_uvs) | + SURFACE_PER_MAT_FLAG, + [BUFFER_INDEX(vbo.tan)] = SURFACE_PER_MAT_FLAG, + [BUFFER_INDEX(vbo.vcol)] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG, + [BUFFER_INDEX(vbo.sculpt_data)] = BATCH_FLAG(sculpt_overlays), + [BUFFER_INDEX(vbo.orco)] = SURFACE_PER_MAT_FLAG, + [BUFFER_INDEX(vbo.edit_data)] = BATCH_FLAG(edit_triangles, edit_edges, edit_vertices), + [BUFFER_INDEX(vbo.edituv_data)] = BATCH_FLAG(edituv_faces, + edituv_faces_stretch_area, + edituv_faces_stretch_angle, + edituv_edges, + edituv_verts), + [BUFFER_INDEX(vbo.edituv_stretch_area)] = BATCH_FLAG(edituv_faces_stretch_area), + [BUFFER_INDEX(vbo.edituv_stretch_angle)] = BATCH_FLAG(edituv_faces_stretch_angle), + [BUFFER_INDEX(vbo.mesh_analysis)] = BATCH_FLAG(edit_mesh_analysis), + [BUFFER_INDEX(vbo.fdots_pos)] = BATCH_FLAG(edit_fdots, edit_selection_fdots), + [BUFFER_INDEX(vbo.fdots_nor)] = BATCH_FLAG(edit_fdots), + [BUFFER_INDEX(vbo.fdots_uv)] = BATCH_FLAG(edituv_fdots), + [BUFFER_INDEX(vbo.fdots_edituv_data)] = BATCH_FLAG(edituv_fdots), + [BUFFER_INDEX(vbo.skin_roots)] = BATCH_FLAG(edit_skin_roots), + [BUFFER_INDEX(vbo.vert_idx)] = BATCH_FLAG(edit_selection_verts), + [BUFFER_INDEX(vbo.edge_idx)] = BATCH_FLAG(edit_selection_edges), + [BUFFER_INDEX(vbo.poly_idx)] = BATCH_FLAG(edit_selection_faces), + [BUFFER_INDEX(vbo.fdot_idx)] = BATCH_FLAG(edit_selection_fdots), + + [BUFFER_INDEX(ibo.tris)] = BATCH_FLAG(surface, + surface_weights, + edit_triangles, + edit_lnor, + edit_mesh_analysis, + edit_selection_faces, + sculpt_overlays), + [BUFFER_INDEX(ibo.lines)] = BATCH_FLAG( + edit_edges, edit_selection_edges, all_edges, wire_edges), + [BUFFER_INDEX(ibo.lines_loose)] = BATCH_FLAG(loose_edges), + [BUFFER_INDEX(ibo.points)] = BATCH_FLAG(edit_vnor, edit_vertices, edit_selection_verts), + [BUFFER_INDEX(ibo.fdots)] = BATCH_FLAG(edit_fdots, edit_selection_fdots), + [BUFFER_INDEX(ibo.lines_paint_mask)] = BATCH_FLAG(wire_loops), + [BUFFER_INDEX(ibo.lines_adjacency)] = BATCH_FLAG(edge_detection), + [BUFFER_INDEX(ibo.edituv_tris)] = BATCH_FLAG( + edituv_faces, edituv_faces_stretch_area, edituv_faces_stretch_angle), + [BUFFER_INDEX(ibo.edituv_lines)] = BATCH_FLAG(edituv_edges, wire_loops_uvs), + [BUFFER_INDEX(ibo.edituv_points)] = BATCH_FLAG(edituv_verts), + [BUFFER_INDEX(ibo.edituv_fdots)] = BATCH_FLAG(edituv_fdots), + [TRIS_PER_MAT_INDEX] = SURFACE_PER_MAT_FLAG, }; #ifndef NDEBUG @@ -231,7 +232,7 @@ static void mesh_batch_cache_discard_batch(MeshBatchCache *cache, const DRWBatch } } - if (batch_map & (1u << MBC_BATCH_INDEX(surface_per_mat))) { + if (batch_map & SURFACE_PER_MAT_FLAG) { mesh_batch_cache_discard_surface_batches(cache); } } @@ -661,8 +662,7 @@ static void mesh_batch_cache_init(Mesh *me) cache->mat_len = mesh_render_mat_len_get(me); cache->surface_per_mat = MEM_callocN(sizeof(*cache->surface_per_mat) * cache->mat_len, __func__); - cache->final.tris_per_mat = MEM_callocN(sizeof(*cache->final.tris_per_mat) * cache->mat_len, - __func__); + cache->tris_per_mat = MEM_callocN(sizeof(*cache->tris_per_mat) * cache->mat_len, __func__); cache->is_dirty = false; cache->batch_ready = 0; @@ -688,8 +688,8 @@ static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache, const struct DRW_MeshWeightState *wstate) { if (!drw_mesh_weight_state_compare(&cache->weight_state, wstate)) { - FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) { - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.weights); + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.weights); } GPU_BATCH_CLEAR_SAFE(cache->batch.surface_weights); @@ -708,6 +708,9 @@ static void mesh_batch_cache_request_surface_batches(MeshBatchCache *cache) } } +/* Free batches with material-mapped looptris. + * NOTE: The updating of the indices buffers (#tris_per_mat) is handled in the extractors. + * No need to discard they here. */ static void mesh_batch_cache_discard_surface_batches(MeshBatchCache *cache) { GPU_BATCH_DISCARD_SAFE(cache->batch.surface); @@ -719,41 +722,41 @@ static void mesh_batch_cache_discard_surface_batches(MeshBatchCache *cache) static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) { - FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) { - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.uv); - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.tan); - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.vcol); - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.orco); + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.uv); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.tan); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.vcol); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.orco); } - DRWBatchFlag batch_map = MDEPS_CREATE_MAP(vbo.uv, vbo.tan, vbo.vcol, vbo.orco); + DRWBatchFlag batch_map = BATCH_MAP(vbo.uv, vbo.tan, vbo.vcol, vbo.orco); mesh_batch_cache_discard_batch(cache, batch_map); mesh_cd_layers_type_clear(&cache->cd_used); } static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache) { - FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) { - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edituv_stretch_angle); - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edituv_stretch_area); - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.uv); - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edituv_data); - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_uv); - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_edituv_data); - GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_tris); - GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_lines); - GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_points); - GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_fdots); - } - DRWBatchFlag batch_map = MDEPS_CREATE_MAP(vbo.edituv_stretch_angle, - vbo.edituv_stretch_area, - vbo.uv, - vbo.edituv_data, - vbo.fdots_uv, - vbo.fdots_edituv_data, - ibo.edituv_tris, - ibo.edituv_lines, - ibo.edituv_points, - ibo.edituv_fdots); + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_stretch_angle); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_stretch_area); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.uv); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_data); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_uv); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_edituv_data); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_tris); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_lines); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_points); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_fdots); + } + DRWBatchFlag batch_map = BATCH_MAP(vbo.edituv_stretch_angle, + vbo.edituv_stretch_area, + vbo.uv, + vbo.edituv_data, + vbo.fdots_uv, + vbo.fdots_edituv_data, + ibo.edituv_tris, + ibo.edituv_lines, + ibo.edituv_points, + ibo.edituv_fdots); mesh_batch_cache_discard_batch(cache, batch_map); cache->tot_area = 0.0f; @@ -768,20 +771,20 @@ static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache) static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache) { - FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) { - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edituv_data); - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_edituv_data); - GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_tris); - GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_lines); - GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_points); - GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_fdots); - } - DRWBatchFlag batch_map = MDEPS_CREATE_MAP(vbo.edituv_data, - vbo.fdots_edituv_data, - ibo.edituv_tris, - ibo.edituv_lines, - ibo.edituv_points, - ibo.edituv_fdots); + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_data); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_edituv_data); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_tris); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_lines); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_points); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_fdots); + } + DRWBatchFlag batch_map = BATCH_MAP(vbo.edituv_data, + vbo.fdots_edituv_data, + ibo.edituv_tris, + ibo.edituv_lines, + ibo.edituv_points, + ibo.edituv_fdots); mesh_batch_cache_discard_batch(cache, batch_map); } @@ -794,11 +797,11 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode) DRWBatchFlag batch_map; switch (mode) { case BKE_MESH_BATCH_DIRTY_SELECT: - FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) { - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edit_data); - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_nor); + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edit_data); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_nor); } - batch_map = MDEPS_CREATE_MAP(vbo.edit_data, vbo.fdots_nor); + batch_map = BATCH_MAP(vbo.edit_data, vbo.fdots_nor); mesh_batch_cache_discard_batch(cache, batch_map); /* Because visible UVs depends on edit mode selection, discard topology. */ @@ -807,12 +810,12 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode) case BKE_MESH_BATCH_DIRTY_SELECT_PAINT: /* Paint mode selection flag is packed inside the nor attribute. * Note that it can be slow if auto smooth is enabled. (see T63946) */ - FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) { - GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.lines_paint_mask); - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.pos_nor); - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.lnor); + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.lines_paint_mask); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.pos_nor); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.lnor); } - batch_map = MDEPS_CREATE_MAP(ibo.lines_paint_mask, vbo.pos_nor, vbo.lnor); + batch_map = BATCH_MAP(ibo.lines_paint_mask, vbo.pos_nor, vbo.lnor); mesh_batch_cache_discard_batch(cache, batch_map); break; case BKE_MESH_BATCH_DIRTY_ALL: @@ -826,11 +829,11 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode) mesh_batch_cache_discard_uvedit(cache); break; case BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT: - FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) { - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edituv_data); - GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_edituv_data); + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_data); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_edituv_data); } - batch_map = MDEPS_CREATE_MAP(vbo.edituv_data, vbo.fdots_edituv_data); + batch_map = BATCH_MAP(vbo.edituv_data, vbo.fdots_edituv_data); mesh_batch_cache_discard_batch(cache, batch_map); break; default: @@ -838,28 +841,30 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode) } } -static void mesh_buffer_cache_clear(MeshBufferCache *mbufcache) +static void mesh_buffer_list_clear(MeshBufferList *mbuflist) { - GPUVertBuf **vbos = (GPUVertBuf **)&mbufcache->vbo; - GPUIndexBuf **ibos = (GPUIndexBuf **)&mbufcache->ibo; - for (int i = 0; i < sizeof(mbufcache->vbo) / sizeof(void *); i++) { + GPUVertBuf **vbos = (GPUVertBuf **)&mbuflist->vbo; + GPUIndexBuf **ibos = (GPUIndexBuf **)&mbuflist->ibo; + for (int i = 0; i < sizeof(mbuflist->vbo) / sizeof(void *); i++) { GPU_VERTBUF_DISCARD_SAFE(vbos[i]); } - for (int i = 0; i < sizeof(mbufcache->ibo) / sizeof(void *); i++) { + for (int i = 0; i < sizeof(mbuflist->ibo) / sizeof(void *); i++) { GPU_INDEXBUF_DISCARD_SAFE(ibos[i]); } } -static void mesh_buffer_extraction_cache_clear(MeshBufferExtractionCache *extraction_cache) +static void mesh_buffer_cache_clear(MeshBufferCache *mbc) { - MEM_SAFE_FREE(extraction_cache->loose_geom.verts); - MEM_SAFE_FREE(extraction_cache->loose_geom.edges); - extraction_cache->loose_geom.edge_len = 0; - extraction_cache->loose_geom.vert_len = 0; + mesh_buffer_list_clear(&mbc->buff); - MEM_SAFE_FREE(extraction_cache->poly_sorted.tri_first_index); - MEM_SAFE_FREE(extraction_cache->poly_sorted.mat_tri_len); - extraction_cache->poly_sorted.visible_tri_len = 0; + MEM_SAFE_FREE(mbc->loose_geom.verts); + MEM_SAFE_FREE(mbc->loose_geom.edges); + mbc->loose_geom.edge_len = 0; + mbc->loose_geom.vert_len = 0; + + MEM_SAFE_FREE(mbc->poly_sorted.tri_first_index); + MEM_SAFE_FREE(mbc->poly_sorted.mat_tri_len); + mbc->poly_sorted.visible_tri_len = 0; } static void mesh_batch_cache_clear(Mesh *me) @@ -868,18 +873,14 @@ static void mesh_batch_cache_clear(Mesh *me) if (!cache) { return; } - FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) { - mesh_buffer_cache_clear(mbufcache); + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + mesh_buffer_cache_clear(mbc); } - mesh_buffer_extraction_cache_clear(&cache->final_extraction_cache); - mesh_buffer_extraction_cache_clear(&cache->cage_extraction_cache); - mesh_buffer_extraction_cache_clear(&cache->uv_cage_extraction_cache); - for (int i = 0; i < cache->mat_len; i++) { - GPU_INDEXBUF_DISCARD_SAFE(cache->final.tris_per_mat[i]); + GPU_INDEXBUF_DISCARD_SAFE(cache->tris_per_mat[i]); } - MEM_SAFE_FREE(cache->final.tris_per_mat); + MEM_SAFE_FREE(cache->tris_per_mat); for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) { GPUBatch **batch = (GPUBatch **)&cache->batch; @@ -1083,8 +1084,8 @@ GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(Mesh *me) /* Request surface to trigger the vbo filling. Otherwise it may do nothing. */ mesh_batch_cache_request_surface_batches(cache); - DRW_vbo_request(NULL, &cache->final.vbo.pos_nor); - return cache->final.vbo.pos_nor; + DRW_vbo_request(NULL, &cache->final.buff.vbo.pos_nor); + return cache->final.buff.vbo.pos_nor; } /** \} */ @@ -1316,22 +1317,22 @@ static void drw_mesh_batch_cache_check_available(struct TaskGraph *task_graph, M BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0)); } for (int i = 0; i < MBC_VBO_LEN; i++) { - BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->final.vbo)[i])); + BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->final.buff.vbo)[i])); } for (int i = 0; i < MBC_IBO_LEN; i++) { - BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->final.ibo)[i])); + BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->final.buff.ibo)[i])); } for (int i = 0; i < MBC_VBO_LEN; i++) { - BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->cage.vbo)[i])); + BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->cage.buff.vbo)[i])); } for (int i = 0; i < MBC_IBO_LEN; i++) { - BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->cage.ibo)[i])); + BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->cage.buff.ibo)[i])); } for (int i = 0; i < MBC_VBO_LEN; i++) { - BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->uv_cage.vbo)[i])); + BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->uv_cage.buff.vbo)[i])); } for (int i = 0; i < MBC_IBO_LEN; i++) { - BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->uv_cage.ibo)[i])); + BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->uv_cage.buff.ibo)[i])); } } #endif @@ -1414,25 +1415,25 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, * material. */ bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_used, cache->cd_needed); if (cd_overlap == false) { - FOREACH_MESH_BUFFER_CACHE (cache, mbuffercache) { + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { if ((cache->cd_used.uv & cache->cd_needed.uv) != cache->cd_needed.uv) { - GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.uv); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.uv); cd_uv_update = true; } if ((cache->cd_used.tan & cache->cd_needed.tan) != cache->cd_needed.tan || cache->cd_used.tan_orco != cache->cd_needed.tan_orco) { - GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.tan); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.tan); } if (cache->cd_used.orco != cache->cd_needed.orco) { - GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.orco); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.orco); } if (cache->cd_used.sculpt_overlays != cache->cd_needed.sculpt_overlays) { - GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.sculpt_data); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.sculpt_data); } if (((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) || ((cache->cd_used.sculpt_vcol & cache->cd_needed.sculpt_vcol) != cache->cd_needed.sculpt_vcol)) { - GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.vcol); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.vcol); } } /* We can't discard batches at this point as they have been @@ -1454,14 +1455,14 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, const bool is_uvsyncsel = ts && (ts->uv_flag & UV_SYNC_SELECTION); if (cd_uv_update || (cache->is_uvsyncsel != is_uvsyncsel)) { cache->is_uvsyncsel = is_uvsyncsel; - FOREACH_MESH_BUFFER_CACHE (cache, mbuffercache) { - GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.edituv_data); - GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.fdots_uv); - GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.fdots_edituv_data); - GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_tris); - GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_lines); - GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_points); - GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_fdots); + FOREACH_MESH_BUFFER_CACHE (cache, mbc) { + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.edituv_data); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_uv); + GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.fdots_edituv_data); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_tris); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_lines); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_points); + GPU_INDEXBUF_DISCARD_SAFE(mbc->buff.ibo.edituv_fdots); } /* We only clear the batches as they may already have been * referenced. */ @@ -1502,173 +1503,174 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, const bool do_uvcage = is_editmode && !me->edit_mesh->mesh_eval_final->runtime.is_original; - MeshBufferCache *mbufcache = &cache->final; + MeshBufferList *mbuflist = &cache->final.buff; /* Initialize batches and request VBO's & IBO's. */ - MDEPS_ASSERT(batch.surface, ibo.tris, vbo.lnor, vbo.pos_nor, vbo.uv, vbo.vcol); + MDEPS_ASSERT(surface, ibo.tris, vbo.lnor, vbo.pos_nor, vbo.uv, vbo.vcol); if (DRW_batch_requested(cache->batch.surface, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.surface, &mbufcache->ibo.tris); + DRW_ibo_request(cache->batch.surface, &mbuflist->ibo.tris); /* Order matters. First ones override latest VBO's attributes. */ - DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.lnor); - DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.pos_nor); + DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.lnor); + DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.pos_nor); if (cache->cd_used.uv != 0) { - DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.uv); + DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.uv); } if (cache->cd_used.vcol != 0 || cache->cd_used.sculpt_vcol != 0) { - DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.vcol); + DRW_vbo_request(cache->batch.surface, &mbuflist->vbo.vcol); } } - MDEPS_ASSERT(batch.all_verts, vbo.pos_nor); + MDEPS_ASSERT(all_verts, vbo.pos_nor); if (DRW_batch_requested(cache->batch.all_verts, GPU_PRIM_POINTS)) { - DRW_vbo_request(cache->batch.all_verts, &mbufcache->vbo.pos_nor); + DRW_vbo_request(cache->batch.all_verts, &mbuflist->vbo.pos_nor); } - MDEPS_ASSERT(batch.sculpt_overlays, ibo.tris, vbo.pos_nor, vbo.sculpt_data); + MDEPS_ASSERT(sculpt_overlays, ibo.tris, vbo.pos_nor, vbo.sculpt_data); if (DRW_batch_requested(cache->batch.sculpt_overlays, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.sculpt_overlays, &mbufcache->ibo.tris); - DRW_vbo_request(cache->batch.sculpt_overlays, &mbufcache->vbo.pos_nor); - DRW_vbo_request(cache->batch.sculpt_overlays, &mbufcache->vbo.sculpt_data); + DRW_ibo_request(cache->batch.sculpt_overlays, &mbuflist->ibo.tris); + DRW_vbo_request(cache->batch.sculpt_overlays, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.sculpt_overlays, &mbuflist->vbo.sculpt_data); } - MDEPS_ASSERT(batch.all_edges, ibo.lines, vbo.pos_nor); + MDEPS_ASSERT(all_edges, ibo.lines, vbo.pos_nor); if (DRW_batch_requested(cache->batch.all_edges, GPU_PRIM_LINES)) { - DRW_ibo_request(cache->batch.all_edges, &mbufcache->ibo.lines); - DRW_vbo_request(cache->batch.all_edges, &mbufcache->vbo.pos_nor); + DRW_ibo_request(cache->batch.all_edges, &mbuflist->ibo.lines); + DRW_vbo_request(cache->batch.all_edges, &mbuflist->vbo.pos_nor); } - MDEPS_ASSERT(batch.loose_edges, ibo.lines_loose, vbo.pos_nor); + MDEPS_ASSERT(loose_edges, ibo.lines_loose, vbo.pos_nor); if (DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)) { - DRW_ibo_request(NULL, &mbufcache->ibo.lines); - DRW_ibo_request(cache->batch.loose_edges, &mbufcache->ibo.lines_loose); - DRW_vbo_request(cache->batch.loose_edges, &mbufcache->vbo.pos_nor); + DRW_ibo_request(NULL, &mbuflist->ibo.lines); + DRW_ibo_request(cache->batch.loose_edges, &mbuflist->ibo.lines_loose); + DRW_vbo_request(cache->batch.loose_edges, &mbuflist->vbo.pos_nor); } - MDEPS_ASSERT(batch.edge_detection, ibo.lines_adjacency, vbo.pos_nor); + MDEPS_ASSERT(edge_detection, ibo.lines_adjacency, vbo.pos_nor); if (DRW_batch_requested(cache->batch.edge_detection, GPU_PRIM_LINES_ADJ)) { - DRW_ibo_request(cache->batch.edge_detection, &mbufcache->ibo.lines_adjacency); - DRW_vbo_request(cache->batch.edge_detection, &mbufcache->vbo.pos_nor); + DRW_ibo_request(cache->batch.edge_detection, &mbuflist->ibo.lines_adjacency); + DRW_vbo_request(cache->batch.edge_detection, &mbuflist->vbo.pos_nor); } - MDEPS_ASSERT(batch.surface_weights, ibo.tris, vbo.pos_nor, vbo.weights); + MDEPS_ASSERT(surface_weights, ibo.tris, vbo.pos_nor, vbo.weights); if (DRW_batch_requested(cache->batch.surface_weights, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.surface_weights, &mbufcache->ibo.tris); - DRW_vbo_request(cache->batch.surface_weights, &mbufcache->vbo.pos_nor); - DRW_vbo_request(cache->batch.surface_weights, &mbufcache->vbo.weights); + DRW_ibo_request(cache->batch.surface_weights, &mbuflist->ibo.tris); + DRW_vbo_request(cache->batch.surface_weights, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.surface_weights, &mbuflist->vbo.weights); } - MDEPS_ASSERT(batch.wire_loops, ibo.lines_paint_mask, vbo.lnor, vbo.pos_nor); + MDEPS_ASSERT(wire_loops, ibo.lines_paint_mask, vbo.lnor, vbo.pos_nor); if (DRW_batch_requested(cache->batch.wire_loops, GPU_PRIM_LINES)) { - DRW_ibo_request(cache->batch.wire_loops, &mbufcache->ibo.lines_paint_mask); + DRW_ibo_request(cache->batch.wire_loops, &mbuflist->ibo.lines_paint_mask); /* Order matters. First ones override latest VBO's attributes. */ - DRW_vbo_request(cache->batch.wire_loops, &mbufcache->vbo.lnor); - DRW_vbo_request(cache->batch.wire_loops, &mbufcache->vbo.pos_nor); + DRW_vbo_request(cache->batch.wire_loops, &mbuflist->vbo.lnor); + DRW_vbo_request(cache->batch.wire_loops, &mbuflist->vbo.pos_nor); } - MDEPS_ASSERT(batch.wire_edges, ibo.lines, vbo.pos_nor, vbo.edge_fac); + MDEPS_ASSERT(wire_edges, ibo.lines, vbo.pos_nor, vbo.edge_fac); if (DRW_batch_requested(cache->batch.wire_edges, GPU_PRIM_LINES)) { - DRW_ibo_request(cache->batch.wire_edges, &mbufcache->ibo.lines); - DRW_vbo_request(cache->batch.wire_edges, &mbufcache->vbo.pos_nor); - DRW_vbo_request(cache->batch.wire_edges, &mbufcache->vbo.edge_fac); + DRW_ibo_request(cache->batch.wire_edges, &mbuflist->ibo.lines); + DRW_vbo_request(cache->batch.wire_edges, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.wire_edges, &mbuflist->vbo.edge_fac); } - MDEPS_ASSERT(batch.wire_loops_uvs, ibo.edituv_lines, vbo.uv); + MDEPS_ASSERT(wire_loops_uvs, ibo.edituv_lines, vbo.uv); if (DRW_batch_requested(cache->batch.wire_loops_uvs, GPU_PRIM_LINES)) { - DRW_ibo_request(cache->batch.wire_loops_uvs, &mbufcache->ibo.edituv_lines); + DRW_ibo_request(cache->batch.wire_loops_uvs, &mbuflist->ibo.edituv_lines); /* For paint overlay. Active layer should have been queried. */ if (cache->cd_used.uv != 0) { - DRW_vbo_request(cache->batch.wire_loops_uvs, &mbufcache->vbo.uv); + DRW_vbo_request(cache->batch.wire_loops_uvs, &mbuflist->vbo.uv); } } - MDEPS_ASSERT(batch.edit_mesh_analysis, ibo.tris, vbo.pos_nor, vbo.mesh_analysis); + MDEPS_ASSERT(edit_mesh_analysis, ibo.tris, vbo.pos_nor, vbo.mesh_analysis); if (DRW_batch_requested(cache->batch.edit_mesh_analysis, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.edit_mesh_analysis, &mbufcache->ibo.tris); - DRW_vbo_request(cache->batch.edit_mesh_analysis, &mbufcache->vbo.pos_nor); - DRW_vbo_request(cache->batch.edit_mesh_analysis, &mbufcache->vbo.mesh_analysis); + DRW_ibo_request(cache->batch.edit_mesh_analysis, &mbuflist->ibo.tris); + DRW_vbo_request(cache->batch.edit_mesh_analysis, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.edit_mesh_analysis, &mbuflist->vbo.mesh_analysis); } /* Per Material */ - MDEPS_ASSERT( - surface_per_mat, tris_per_mat, vbo.lnor, vbo.pos_nor, vbo.uv, vbo.tan, vbo.vcol, vbo.orco); + MDEPS_ASSERT_FLAG( + SURFACE_PER_MAT_FLAG, vbo.lnor, vbo.pos_nor, vbo.uv, vbo.tan, vbo.vcol, vbo.orco); + MDEPS_ASSERT_INDEX(TRIS_PER_MAT_INDEX, SURFACE_PER_MAT_FLAG); for (int i = 0; i < cache->mat_len; i++) { if (DRW_batch_requested(cache->surface_per_mat[i], GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->surface_per_mat[i], &mbufcache->tris_per_mat[i]); + DRW_ibo_request(cache->surface_per_mat[i], &cache->tris_per_mat[i]); /* Order matters. First ones override latest VBO's attributes. */ - DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.lnor); - DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.pos_nor); + DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.lnor); + DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.pos_nor); if (cache->cd_used.uv != 0) { - DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.uv); + DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.uv); } if ((cache->cd_used.tan != 0) || (cache->cd_used.tan_orco != 0)) { - DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.tan); + DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.tan); } if (cache->cd_used.vcol != 0 || cache->cd_used.sculpt_vcol != 0) { - DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.vcol); + DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.vcol); } if (cache->cd_used.orco != 0) { - DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.orco); + DRW_vbo_request(cache->surface_per_mat[i], &mbuflist->vbo.orco); } } } - mbufcache = (do_cage) ? &cache->cage : &cache->final; + mbuflist = (do_cage) ? &cache->cage.buff : &cache->final.buff; /* Edit Mesh */ - MDEPS_ASSERT(batch.edit_triangles, ibo.tris, vbo.pos_nor, vbo.edit_data); + MDEPS_ASSERT(edit_triangles, ibo.tris, vbo.pos_nor, vbo.edit_data); if (DRW_batch_requested(cache->batch.edit_triangles, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.edit_triangles, &mbufcache->ibo.tris); - DRW_vbo_request(cache->batch.edit_triangles, &mbufcache->vbo.pos_nor); - DRW_vbo_request(cache->batch.edit_triangles, &mbufcache->vbo.edit_data); + DRW_ibo_request(cache->batch.edit_triangles, &mbuflist->ibo.tris); + DRW_vbo_request(cache->batch.edit_triangles, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.edit_triangles, &mbuflist->vbo.edit_data); } - MDEPS_ASSERT(batch.edit_vertices, ibo.points, vbo.pos_nor, vbo.edit_data); + MDEPS_ASSERT(edit_vertices, ibo.points, vbo.pos_nor, vbo.edit_data); if (DRW_batch_requested(cache->batch.edit_vertices, GPU_PRIM_POINTS)) { - DRW_ibo_request(cache->batch.edit_vertices, &mbufcache->ibo.points); - DRW_vbo_request(cache->batch.edit_vertices, &mbufcache->vbo.pos_nor); - DRW_vbo_request(cache->batch.edit_vertices, &mbufcache->vbo.edit_data); + DRW_ibo_request(cache->batch.edit_vertices, &mbuflist->ibo.points); + DRW_vbo_request(cache->batch.edit_vertices, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.edit_vertices, &mbuflist->vbo.edit_data); } - MDEPS_ASSERT(batch.edit_edges, ibo.lines, vbo.pos_nor, vbo.edit_data); + MDEPS_ASSERT(edit_edges, ibo.lines, vbo.pos_nor, vbo.edit_data); if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) { - DRW_ibo_request(cache->batch.edit_edges, &mbufcache->ibo.lines); - DRW_vbo_request(cache->batch.edit_edges, &mbufcache->vbo.pos_nor); - DRW_vbo_request(cache->batch.edit_edges, &mbufcache->vbo.edit_data); + DRW_ibo_request(cache->batch.edit_edges, &mbuflist->ibo.lines); + DRW_vbo_request(cache->batch.edit_edges, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.edit_edges, &mbuflist->vbo.edit_data); } - MDEPS_ASSERT(batch.edit_vnor, ibo.points, vbo.pos_nor); + MDEPS_ASSERT(edit_vnor, ibo.points, vbo.pos_nor); if (DRW_batch_requested(cache->batch.edit_vnor, GPU_PRIM_POINTS)) { - DRW_ibo_request(cache->batch.edit_vnor, &mbufcache->ibo.points); - DRW_vbo_request(cache->batch.edit_vnor, &mbufcache->vbo.pos_nor); + DRW_ibo_request(cache->batch.edit_vnor, &mbuflist->ibo.points); + DRW_vbo_request(cache->batch.edit_vnor, &mbuflist->vbo.pos_nor); } - MDEPS_ASSERT(batch.edit_lnor, ibo.tris, vbo.pos_nor, vbo.lnor); + MDEPS_ASSERT(edit_lnor, ibo.tris, vbo.pos_nor, vbo.lnor); if (DRW_batch_requested(cache->batch.edit_lnor, GPU_PRIM_POINTS)) { - DRW_ibo_request(cache->batch.edit_lnor, &mbufcache->ibo.tris); - DRW_vbo_request(cache->batch.edit_lnor, &mbufcache->vbo.pos_nor); - DRW_vbo_request(cache->batch.edit_lnor, &mbufcache->vbo.lnor); + DRW_ibo_request(cache->batch.edit_lnor, &mbuflist->ibo.tris); + DRW_vbo_request(cache->batch.edit_lnor, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.edit_lnor, &mbuflist->vbo.lnor); } - MDEPS_ASSERT(batch.edit_fdots, ibo.fdots, vbo.fdots_pos, vbo.fdots_nor); + MDEPS_ASSERT(edit_fdots, ibo.fdots, vbo.fdots_pos, vbo.fdots_nor); if (DRW_batch_requested(cache->batch.edit_fdots, GPU_PRIM_POINTS)) { - DRW_ibo_request(cache->batch.edit_fdots, &mbufcache->ibo.fdots); - DRW_vbo_request(cache->batch.edit_fdots, &mbufcache->vbo.fdots_pos); - DRW_vbo_request(cache->batch.edit_fdots, &mbufcache->vbo.fdots_nor); + DRW_ibo_request(cache->batch.edit_fdots, &mbuflist->ibo.fdots); + DRW_vbo_request(cache->batch.edit_fdots, &mbuflist->vbo.fdots_pos); + DRW_vbo_request(cache->batch.edit_fdots, &mbuflist->vbo.fdots_nor); } - MDEPS_ASSERT(batch.edit_skin_roots, vbo.skin_roots); + MDEPS_ASSERT(edit_skin_roots, vbo.skin_roots); if (DRW_batch_requested(cache->batch.edit_skin_roots, GPU_PRIM_POINTS)) { - DRW_vbo_request(cache->batch.edit_skin_roots, &mbufcache->vbo.skin_roots); + DRW_vbo_request(cache->batch.edit_skin_roots, &mbuflist->vbo.skin_roots); } /* Selection */ - MDEPS_ASSERT(batch.edit_selection_verts, ibo.points, vbo.pos_nor, vbo.vert_idx); + MDEPS_ASSERT(edit_selection_verts, ibo.points, vbo.pos_nor, vbo.vert_idx); if (DRW_batch_requested(cache->batch.edit_selection_verts, GPU_PRIM_POINTS)) { - DRW_ibo_request(cache->batch.edit_selection_verts, &mbufcache->ibo.points); - DRW_vbo_request(cache->batch.edit_selection_verts, &mbufcache->vbo.pos_nor); - DRW_vbo_request(cache->batch.edit_selection_verts, &mbufcache->vbo.vert_idx); + DRW_ibo_request(cache->batch.edit_selection_verts, &mbuflist->ibo.points); + DRW_vbo_request(cache->batch.edit_selection_verts, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.edit_selection_verts, &mbuflist->vbo.vert_idx); } - MDEPS_ASSERT(batch.edit_selection_edges, ibo.lines, vbo.pos_nor, vbo.edge_idx); + MDEPS_ASSERT(edit_selection_edges, ibo.lines, vbo.pos_nor, vbo.edge_idx); if (DRW_batch_requested(cache->batch.edit_selection_edges, GPU_PRIM_LINES)) { - DRW_ibo_request(cache->batch.edit_selection_edges, &mbufcache->ibo.lines); - DRW_vbo_request(cache->batch.edit_selection_edges, &mbufcache->vbo.pos_nor); - DRW_vbo_request(cache->batch.edit_selection_edges, &mbufcache->vbo.edge_idx); + DRW_ibo_request(cache->batch.edit_selection_edges, &mbuflist->ibo.lines); + DRW_vbo_request(cache->batch.edit_selection_edges, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.edit_selection_edges, &mbuflist->vbo.edge_idx); } - MDEPS_ASSERT(batch.edit_selection_faces, ibo.tris, vbo.pos_nor, vbo.poly_idx); + MDEPS_ASSERT(edit_selection_faces, ibo.tris, vbo.pos_nor, vbo.poly_idx); if (DRW_batch_requested(cache->batch.edit_selection_faces, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.edit_selection_faces, &mbufcache->ibo.tris); - DRW_vbo_request(cache->batch.edit_selection_faces, &mbufcache->vbo.pos_nor); - DRW_vbo_request(cache->batch.edit_selection_faces, &mbufcache->vbo.poly_idx); + DRW_ibo_request(cache->batch.edit_selection_faces, &mbuflist->ibo.tris); + DRW_vbo_request(cache->batch.edit_selection_faces, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.edit_selection_faces, &mbuflist->vbo.poly_idx); } - MDEPS_ASSERT(batch.edit_selection_fdots, ibo.fdots, vbo.fdots_pos, vbo.fdot_idx); + MDEPS_ASSERT(edit_selection_fdots, ibo.fdots, vbo.fdots_pos, vbo.fdot_idx); if (DRW_batch_requested(cache->batch.edit_selection_fdots, GPU_PRIM_POINTS)) { - DRW_ibo_request(cache->batch.edit_selection_fdots, &mbufcache->ibo.fdots); - DRW_vbo_request(cache->batch.edit_selection_fdots, &mbufcache->vbo.fdots_pos); - DRW_vbo_request(cache->batch.edit_selection_fdots, &mbufcache->vbo.fdot_idx); + DRW_ibo_request(cache->batch.edit_selection_fdots, &mbuflist->ibo.fdots); + DRW_vbo_request(cache->batch.edit_selection_fdots, &mbuflist->vbo.fdots_pos); + DRW_vbo_request(cache->batch.edit_selection_fdots, &mbuflist->vbo.fdot_idx); } /** @@ -1676,54 +1678,54 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, * but the selection code for UVs needs to support it first. So for now, only * display the cage in all cases. */ - mbufcache = (do_uvcage) ? &cache->uv_cage : &cache->final; + mbuflist = (do_uvcage) ? &cache->uv_cage.buff : &cache->final.buff; /* Edit UV */ - MDEPS_ASSERT(batch.edituv_faces, ibo.edituv_tris, vbo.uv, vbo.edituv_data); + MDEPS_ASSERT(edituv_faces, ibo.edituv_tris, vbo.uv, vbo.edituv_data); if (DRW_batch_requested(cache->batch.edituv_faces, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.edituv_faces, &mbufcache->ibo.edituv_tris); - DRW_vbo_request(cache->batch.edituv_faces, &mbufcache->vbo.uv); - DRW_vbo_request(cache->batch.edituv_faces, &mbufcache->vbo.edituv_data); + DRW_ibo_request(cache->batch.edituv_faces, &mbuflist->ibo.edituv_tris); + DRW_vbo_request(cache->batch.edituv_faces, &mbuflist->vbo.uv); + DRW_vbo_request(cache->batch.edituv_faces, &mbuflist->vbo.edituv_data); } - MDEPS_ASSERT(batch.edituv_faces_stretch_area, + MDEPS_ASSERT(edituv_faces_stretch_area, ibo.edituv_tris, vbo.uv, vbo.edituv_data, vbo.edituv_stretch_area); if (DRW_batch_requested(cache->batch.edituv_faces_stretch_area, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->ibo.edituv_tris); - DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->vbo.uv); - DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->vbo.edituv_data); - DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbufcache->vbo.edituv_stretch_area); + DRW_ibo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->ibo.edituv_tris); + DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.uv); + DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.edituv_data); + DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.edituv_stretch_area); } - MDEPS_ASSERT(batch.edituv_faces_stretch_angle, + MDEPS_ASSERT(edituv_faces_stretch_angle, ibo.edituv_tris, vbo.uv, vbo.edituv_data, vbo.edituv_stretch_angle); if (DRW_batch_requested(cache->batch.edituv_faces_stretch_angle, GPU_PRIM_TRIS)) { - DRW_ibo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->ibo.edituv_tris); - DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->vbo.uv); - DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->vbo.edituv_data); - DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbufcache->vbo.edituv_stretch_angle); + DRW_ibo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->ibo.edituv_tris); + DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.uv); + DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.edituv_data); + DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.edituv_stretch_angle); } - MDEPS_ASSERT(batch.edituv_edges, ibo.edituv_lines, vbo.uv, vbo.edituv_data); + MDEPS_ASSERT(edituv_edges, ibo.edituv_lines, vbo.uv, vbo.edituv_data); if (DRW_batch_requested(cache->batch.edituv_edges, GPU_PRIM_LINES)) { - DRW_ibo_request(cache->batch.edituv_edges, &mbufcache->ibo.edituv_lines); - DRW_vbo_request(cache->batch.edituv_edges, &mbufcache->vbo.uv); - DRW_vbo_request(cache->batch.edituv_edges, &mbufcache->vbo.edituv_data); + DRW_ibo_request(cache->batch.edituv_edges, &mbuflist->ibo.edituv_lines); + DRW_vbo_request(cache->batch.edituv_edges, &mbuflist->vbo.uv); + DRW_vbo_request(cache->batch.edituv_edges, &mbuflist->vbo.edituv_data); } - MDEPS_ASSERT(batch.edituv_verts, ibo.edituv_points, vbo.uv, vbo.edituv_data); + MDEPS_ASSERT(edituv_verts, ibo.edituv_points, vbo.uv, vbo.edituv_data); if (DRW_batch_requested(cache->batch.edituv_verts, GPU_PRIM_POINTS)) { - DRW_ibo_request(cache->batch.edituv_verts, &mbufcache->ibo.edituv_points); - DRW_vbo_request(cache->batch.edituv_verts, &mbufcache->vbo.uv); - DRW_vbo_request(cache->batch.edituv_verts, &mbufcache->vbo.edituv_data); + DRW_ibo_request(cache->batch.edituv_verts, &mbuflist->ibo.edituv_points); + DRW_vbo_request(cache->batch.edituv_verts, &mbuflist->vbo.uv); + DRW_vbo_request(cache->batch.edituv_verts, &mbuflist->vbo.edituv_data); } - MDEPS_ASSERT(batch.edituv_fdots, ibo.edituv_fdots, vbo.fdots_uv, vbo.fdots_edituv_data); + MDEPS_ASSERT(edituv_fdots, ibo.edituv_fdots, vbo.fdots_uv, vbo.fdots_edituv_data); if (DRW_batch_requested(cache->batch.edituv_fdots, GPU_PRIM_POINTS)) { - DRW_ibo_request(cache->batch.edituv_fdots, &mbufcache->ibo.edituv_fdots); - DRW_vbo_request(cache->batch.edituv_fdots, &mbufcache->vbo.fdots_uv); - DRW_vbo_request(cache->batch.edituv_fdots, &mbufcache->vbo.fdots_edituv_data); + DRW_ibo_request(cache->batch.edituv_fdots, &mbuflist->ibo.edituv_fdots); + DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_uv); + DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_edituv_data); } MDEPS_ASSERT_MAP(vbo.lnor); @@ -1762,7 +1764,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, MDEPS_ASSERT_MAP(ibo.edituv_points); MDEPS_ASSERT_MAP(ibo.edituv_fdots); - MDEPS_ASSERT_MAP(tris_per_mat); + MDEPS_ASSERT_MAP_INDEX(TRIS_PER_MAT_INDEX); /* Meh loose Scene const correctness here. */ const bool use_subsurf_fdots = scene ? BKE_modifiers_uses_subsurf_facedots(scene, ob) : false; @@ -1771,7 +1773,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, mesh_buffer_cache_create_requested(task_graph, cache, &cache->uv_cage, - &cache->uv_cage_extraction_cache, me, is_editmode, is_paint_mode, @@ -1789,7 +1790,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, mesh_buffer_cache_create_requested(task_graph, cache, &cache->cage, - &cache->cage_extraction_cache, me, is_editmode, is_paint_mode, @@ -1806,7 +1806,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, mesh_buffer_cache_create_requested(task_graph, cache, &cache->final, - &cache->final_extraction_cache, me, is_editmode, is_paint_mode, diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.c b/source/blender/draw/intern/mesh_extractors/extract_mesh.c index 53827dcc7d9..44de07c8594 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.c +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.c @@ -33,11 +33,11 @@ #include "draw_cache_impl.h" -void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferCache *mbc) +void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuflist) { /* NOTE: POINTER_OFFSET on windows platforms casts internally to `void *`, but on GCC/CLANG to - * `MeshBufferCache *`. What shows a different usage versus intent. */ - void **buffer_ptr = (void **)POINTER_OFFSET(mbc, extractor->mesh_buffer_offset); + * `MeshBufferList *`. What shows a different usage versus intent. */ + void **buffer_ptr = (void **)POINTER_OFFSET(mbuflist, extractor->mesh_buffer_offset); void *buffer = *buffer_ptr; BLI_assert(buffer); return buffer; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.h index f24ccf1a028..d9f397fd8b8 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.h @@ -232,7 +232,7 @@ typedef struct MeshExtract { /** Used to know if the element callbacks are thread-safe and can be parallelized. */ bool use_threading; /** - * Offset in bytes of the buffer inside a MeshBufferCache instance. Points to a vertex or index + * Offset in bytes of the buffer inside a MeshBufferList instance. Points to a vertex or index * buffer. */ size_t mesh_buffer_offset; @@ -252,11 +252,11 @@ MeshRenderData *mesh_render_data_create(Mesh *me, void mesh_render_data_free(MeshRenderData *mr); void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_flag); void mesh_render_data_update_loose_geom(MeshRenderData *mr, - MeshBufferExtractionCache *cache, + MeshBufferCache *cache, const eMRIterType iter_type, const eMRDataType data_flag); void mesh_render_data_update_polys_sorted(MeshRenderData *mr, - MeshBufferExtractionCache *cache, + MeshBufferCache *cache, const eMRDataType data_flag); void mesh_render_data_update_looptris(MeshRenderData *mr, const eMRIterType iter_type, @@ -270,7 +270,7 @@ typedef struct EditLoopData { uchar bweight; } EditLoopData; -void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferCache *mbc); +void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuflist); eMRIterType mesh_extract_iter_type(const MeshExtract *ext); const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor, const bool do_hq_normals, diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc index 5bd5f7adaa8..d06fb91411e 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc @@ -104,7 +104,7 @@ constexpr MeshExtract create_extractor_edituv_tris() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUvElem_Data); extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_tris); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.edituv_tris); return extractor; } @@ -194,7 +194,7 @@ constexpr MeshExtract create_extractor_edituv_lines() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUvElem_Data); extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_lines); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.edituv_lines); return extractor; } @@ -278,7 +278,7 @@ constexpr MeshExtract create_extractor_edituv_points() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUvElem_Data); extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_points); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.edituv_points); return extractor; } @@ -374,7 +374,7 @@ constexpr MeshExtract create_extractor_edituv_fdots() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUvElem_Data); extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_fdots); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.edituv_fdots); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc index 0f41702a22c..ea58e1aeed8 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc @@ -105,7 +105,7 @@ constexpr MeshExtract create_extractor_fdots() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(GPUIndexBufBuilder); extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.fdots); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.fdots); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc index 0096da9e56f..54f5611106f 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc @@ -168,7 +168,7 @@ constexpr MeshExtract create_extractor_lines() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(GPUIndexBufBuilder); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.lines); return extractor; } @@ -180,12 +180,12 @@ constexpr MeshExtract create_extractor_lines() static void extract_lines_loose_subbuffer(const MeshRenderData *mr, struct MeshBatchCache *cache) { - BLI_assert(cache->final.ibo.lines); + BLI_assert(cache->final.buff.ibo.lines); /* Multiply by 2 because these are edges indices. */ const int start = mr->edge_len * 2; const int len = mr->edge_loose_len * 2; GPU_indexbuf_create_subrange_in_place( - cache->final.ibo.lines_loose, cache->final.ibo.lines, start, len); + cache->final.buff.ibo.lines_loose, cache->final.buff.ibo.lines, start, len); cache->no_loose_wire = (len == 0); } @@ -213,7 +213,7 @@ constexpr MeshExtract create_extractor_lines_with_lines_loose() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(GPUIndexBufBuilder); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.lines); return extractor; } @@ -228,7 +228,7 @@ static void extract_lines_loose_only_init(const MeshRenderData *mr, void *buf, void *UNUSED(tls_data)) { - BLI_assert(buf == cache->final.ibo.lines_loose); + BLI_assert(buf == cache->final.buff.ibo.lines_loose); UNUSED_VARS_NDEBUG(buf); extract_lines_loose_subbuffer(mr, cache); } @@ -240,7 +240,7 @@ constexpr MeshExtract create_extractor_lines_loose_only() extractor.data_type = MR_DATA_LOOSE_GEOM; extractor.data_size = 0; extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_loose); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.lines_loose); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc index 7a37cf50264..522afcd44a1 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc @@ -185,7 +185,7 @@ constexpr MeshExtract create_extractor_lines_adjacency() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_LineAdjacency_Data); extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_adjacency); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.lines_adjacency); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc index 5def7edb75a..494a43e97d1 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc @@ -114,7 +114,7 @@ constexpr MeshExtract create_extractor_lines_paint_mask() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_LinePaintMask_Data); extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_paint_mask); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.lines_paint_mask); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc index cc1a19b8d26..b801ba04162 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc @@ -169,7 +169,7 @@ constexpr MeshExtract create_extractor_points() extractor.use_threading = true; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(GPUIndexBufBuilder); - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.points); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.points); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc index e346177af52..54e733d3d86 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc @@ -105,20 +105,19 @@ static void extract_tris_finish(const MeshRenderData *mr, /* Create ibo sub-ranges. Always do this to avoid error when the standard surface batch * is created before the surfaces-per-material. */ - if (mr->use_final_mesh && cache->final.tris_per_mat) { - MeshBufferCache *mbc_final = &cache->final; + if (mr->use_final_mesh && cache->tris_per_mat) { int mat_start = 0; for (int i = 0; i < mr->mat_len; i++) { /* These IBOs have not been queried yet but we create them just in case they are needed * later since they are not tracked by mesh_buffer_cache_create_requested(). */ - if (mbc_final->tris_per_mat[i] == nullptr) { - mbc_final->tris_per_mat[i] = GPU_indexbuf_calloc(); + if (cache->tris_per_mat[i] == nullptr) { + cache->tris_per_mat[i] = GPU_indexbuf_calloc(); } const int mat_tri_len = mr->poly_sorted.mat_tri_len[i]; /* Multiply by 3 because these are triangle indices. */ const int start = mat_start * 3; const int len = mat_tri_len * 3; - GPU_indexbuf_create_subrange_in_place(mbc_final->tris_per_mat[i], ibo, start, len); + GPU_indexbuf_create_subrange_in_place(cache->tris_per_mat[i], ibo, start, len); mat_start += mat_tri_len; } } @@ -135,7 +134,7 @@ constexpr MeshExtract create_extractor_tris() extractor.data_type = MR_DATA_LOOPTRI | MR_DATA_POLYS_SORTED; extractor.data_size = sizeof(GPUIndexBufBuilder); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.tris); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.tris); return extractor; } @@ -197,17 +196,16 @@ static void extract_tris_single_mat_finish(const MeshRenderData *mr, /* Create ibo sub-ranges. Always do this to avoid error when the standard surface batch * is created before the surfaces-per-material. */ - if (mr->use_final_mesh && cache->final.tris_per_mat) { - MeshBufferCache *mbc = &cache->final; + if (mr->use_final_mesh && cache->tris_per_mat) { for (int i = 0; i < mr->mat_len; i++) { /* These IBOs have not been queried yet but we create them just in case they are needed * later since they are not tracked by mesh_buffer_cache_create_requested(). */ - if (mbc->tris_per_mat[i] == nullptr) { - mbc->tris_per_mat[i] = GPU_indexbuf_calloc(); + if (cache->tris_per_mat[i] == nullptr) { + cache->tris_per_mat[i] = GPU_indexbuf_calloc(); } /* Multiply by 3 because these are triangle indices. */ const int len = mr->tri_len * 3; - GPU_indexbuf_create_subrange_in_place(mbc->tris_per_mat[i], ibo, 0, len); + GPU_indexbuf_create_subrange_in_place(cache->tris_per_mat[i], ibo, 0, len); } } } @@ -223,7 +221,7 @@ constexpr MeshExtract create_extractor_tris_single_mat() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(GPUIndexBufBuilder); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.tris); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.tris); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc index 302616d4da9..2e2444a8e3d 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc @@ -228,7 +228,7 @@ constexpr MeshExtract create_extractor_edge_fac() extractor.data_type = MR_DATA_POLY_NOR; extractor.data_size = sizeof(MeshExtract_EdgeFac_Data); extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edge_fac); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.edge_fac); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc index a7efb9c8a1b..5232346e51e 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc @@ -253,7 +253,7 @@ constexpr MeshExtract create_extractor_edit_data() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(EditLoopData *); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edit_data); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.edit_data); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc index 0378aadabd0..b8494428eed 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc @@ -128,7 +128,7 @@ constexpr MeshExtract create_extractor_edituv_data() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUVData_Data); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_data); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.edituv_data); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc index a60c0182e89..a947d98f955 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc @@ -222,7 +222,7 @@ constexpr MeshExtract create_extractor_edituv_edituv_stretch_angle() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_StretchAngle_Data); extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_stretch_angle); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.edituv_stretch_angle); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc index d79ac493c33..3db8cd79af5 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc @@ -143,7 +143,7 @@ constexpr MeshExtract create_extractor_edituv_stretch_area() extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_stretch_area); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.edituv_stretch_area); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc index b7182d1b60f..28592417183 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc @@ -89,7 +89,7 @@ constexpr MeshExtract create_extractor_fdots_edituv_data() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUVFdotData_Data); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_edituv_data); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.fdots_edituv_data); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc index 5e4ad54f7b6..fed66f0057d 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc @@ -105,7 +105,7 @@ constexpr MeshExtract create_extractor_fdots_nor() extractor.data_type = MR_DATA_LOOP_NOR; extractor.data_size = 0; extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_nor); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.fdots_nor); return extractor; } @@ -186,7 +186,7 @@ constexpr MeshExtract create_extractor_fdots_nor_hq() extractor.data_type = MR_DATA_LOOP_NOR; extractor.data_size = 0; extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_nor); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.fdots_nor); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc index e765fb8a8bf..33f9180e122 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc @@ -106,7 +106,7 @@ constexpr MeshExtract create_extractor_fdots_pos() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(float(*)[3]); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_pos); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.fdots_pos); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc index 042a0d2debe..6fe714def30 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc @@ -114,7 +114,7 @@ constexpr MeshExtract create_extractor_fdots_uv() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_FdotUV_Data); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_uv); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.fdots_uv); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc index 8344a615cbe..f9f66c27aaa 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc @@ -116,7 +116,7 @@ constexpr MeshExtract create_extractor_lnor() extractor.data_type = MR_DATA_LOOP_NOR; extractor.data_size = sizeof(GPUPackedNormal *); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.lnor); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.lnor); return extractor; } @@ -214,7 +214,7 @@ constexpr MeshExtract create_extractor_lnor_hq() extractor.data_type = MR_DATA_LOOP_NOR; extractor.data_size = sizeof(gpuHQNor *); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.lnor); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.lnor); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc index 075d54e268e..33a33c81bc2 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc @@ -641,7 +641,7 @@ constexpr MeshExtract create_extractor_mesh_analysis() extractor.data_type = MR_DATA_POLY_NOR | MR_DATA_LOOPTRI; extractor.data_size = 0; extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.mesh_analysis); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.mesh_analysis); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc index 269c0343e32..c5187a47892 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc @@ -102,7 +102,7 @@ constexpr MeshExtract create_extractor_orco() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_Orco_Data); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.orco); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.orco); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc index b8e5dcb613f..eb9a138590c 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc @@ -208,7 +208,7 @@ constexpr MeshExtract create_extractor_pos_nor() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_PosNor_Data); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.pos_nor); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.pos_nor); return extractor; } @@ -401,7 +401,7 @@ constexpr MeshExtract create_extractor_pos_nor_hq() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_PosNorHQ_Data); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.pos_nor); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.pos_nor); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc index dbb1e1f880b..fd91bc5258f 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc @@ -128,7 +128,7 @@ constexpr MeshExtract create_extractor_sculpt_data() extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.sculpt_data); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.sculpt_data); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc index cd8d46901c5..5ac30dd3be9 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc @@ -205,7 +205,7 @@ constexpr MeshExtract create_extractor_poly_idx() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(uint32_t *); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.poly_idx); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.poly_idx); return extractor; } @@ -220,7 +220,7 @@ constexpr MeshExtract create_extractor_edge_idx() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(uint32_t *); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edge_idx); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.edge_idx); return extractor; } @@ -237,7 +237,7 @@ constexpr MeshExtract create_extractor_vert_idx() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(uint32_t *); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.vert_idx); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.vert_idx); return extractor; } @@ -279,7 +279,7 @@ constexpr MeshExtract create_extractor_fdot_idx() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(uint32_t *); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdot_idx); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.fdot_idx); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc index ffca01d00dd..1847a360837 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc @@ -80,7 +80,7 @@ constexpr MeshExtract create_extractor_skin_roots() extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.skin_roots); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.skin_roots); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc index 8f36bfdf1ef..1f8776fc98e 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc @@ -226,7 +226,7 @@ constexpr MeshExtract create_extractor_tan() extractor.data_type = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI; extractor.data_size = 0; extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.tan); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.tan); return extractor; } @@ -252,7 +252,7 @@ constexpr MeshExtract create_extractor_tan_hq() extractor.data_type = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI; extractor.data_size = 0; extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.tan); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.tan); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc index 013da7d674a..af279b08a59 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc @@ -123,7 +123,7 @@ constexpr MeshExtract create_extractor_uv() extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.uv); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.uv); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc index d810acfb617..2c7770c8e72 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc @@ -178,7 +178,7 @@ constexpr MeshExtract create_extractor_vcol() extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.vcol); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.vcol); return extractor; } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc index c547a453aeb..bdb1410a755 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc @@ -176,7 +176,7 @@ constexpr MeshExtract create_extractor_weights() extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_Weight_Data); extractor.use_threading = true; - extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.weights); + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.weights); return extractor; } diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index 39fb2882e4b..b7deea5069e 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -576,7 +576,7 @@ static int paste_from_file_exec(bContext *C, wmOperator *op) char *path; int retval; - path = RNA_string_get_alloc(op->ptr, "filepath", NULL, 0); + path = RNA_string_get_alloc(op->ptr, "filepath", NULL, 0, NULL); retval = paste_from_file(C, op->reports, path); MEM_freeN(path); @@ -1627,7 +1627,7 @@ static int insert_text_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - inserted_utf8 = RNA_string_get_alloc(op->ptr, "text", NULL, 0); + inserted_utf8 = RNA_string_get_alloc(op->ptr, "text", NULL, 0, NULL); len = BLI_strlen_utf8(inserted_utf8); inserted_text = MEM_callocN(sizeof(char32_t) * (len + 1), "FONT_insert_text"); diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index 6e4002fcc0a..1d51a3e77cf 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -53,8 +53,9 @@ typedef enum { #define NODE_EDGE_PAN_INSIDE_PAD 2 #define NODE_EDGE_PAN_OUTSIDE_PAD 0 /* Disable clamping for node panning, use whole screen. */ #define NODE_EDGE_PAN_SPEED_RAMP 1 -#define NODE_EDGE_PAN_MAX_SPEED 40 /* In UI units per second, slower than default. */ -#define NODE_EDGE_PAN_DELAY 1.0f +#define NODE_EDGE_PAN_MAX_SPEED 26 /* In UI units per second, slower than default. */ +#define NODE_EDGE_PAN_DELAY 0.5f +#define NODE_EDGE_PAN_ZOOM_INFLUENCE 0.5f /* space_node.c */ diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index cb6fb0dba60..69ac48d842f 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -137,6 +137,7 @@ int BIF_countTransformOrientation(const struct bContext *C); #define P_GPENCIL_EDIT (1 << 13) #define P_CURSOR_EDIT (1 << 14) #define P_CLNOR_INVALIDATE (1 << 15) +#define P_VIEW2D_EDGE_PAN (1 << 16) /* For properties performed when confirming the transformation. */ #define P_POST_TRANSFORM (1 << 19) diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index c99c7f681b3..dde8a637e05 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -185,7 +185,7 @@ typedef enum ThemeColorID { TH_NODE_LAYOUT, TH_NODE_SHADER, TH_NODE_INTERFACE, - TH_NODE_CONVERTOR, + TH_NODE_CONVERTER, TH_NODE_GROUP, TH_NODE_FRAME, TH_NODE_MATTE, diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 4ee7df89487..e3c02b4c249 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -26,6 +26,7 @@ #pragma once #include "BLI_compiler_attrs.h" +#include "BLI_rect.h" #ifdef __cplusplus extern "C" { @@ -321,6 +322,14 @@ typedef struct View2DEdgePanData { float max_speed; /** Delay in seconds before maximum speed is reached. */ float delay; + /** Influence factor for view zoom: + * 0 = Constant speed in UI units + * 1 = Constant speed in view space, UI speed slows down when zooming out + */ + float zoom_influence; + + /** Initial view rect. */ + rctf initial_rect; /** Amount to move view relative to zoom. */ float facx, facy; @@ -338,7 +347,8 @@ void UI_view2d_edge_pan_init(struct bContext *C, float outside_pad, float speed_ramp, float max_speed, - float delay); + float delay, + float zoom_influence); void UI_view2d_edge_pan_reset(struct View2DEdgePanData *vpd); @@ -350,6 +360,8 @@ void UI_view2d_edge_pan_apply_event(struct bContext *C, struct View2DEdgePanData *vpd, const struct wmEvent *event); +void UI_view2d_edge_pan_cancel(struct bContext *C, struct View2DEdgePanData *vpd); + void UI_view2d_edge_pan_operator_properties(struct wmOperatorType *ot); void UI_view2d_edge_pan_operator_properties_ex(struct wmOperatorType *ot, @@ -357,7 +369,8 @@ void UI_view2d_edge_pan_operator_properties_ex(struct wmOperatorType *ot, float outside_pad, float speed_ramp, float max_speed, - float delay); + float delay, + float zoom_influence); /* Initialize panning data with operator settings. */ void UI_view2d_edge_pan_operator_init(struct bContext *C, diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 76f6640c714..a618daec4bc 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -3350,7 +3350,7 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in if (pbuf) { if (UI_but_is_utf8(but)) { - buf_len -= BLI_utf8_invalid_strip(pbuf, (size_t)buf_len); + buf_len -= BLI_str_utf8_invalid_strip(pbuf, (size_t)buf_len); } ui_textedit_insert_buf(but, data, pbuf, buf_len); @@ -3527,7 +3527,7 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data) if (but) { if (UI_but_is_utf8(but)) { - const int strip = BLI_utf8_invalid_strip(but->editstr, strlen(but->editstr)); + const int strip = BLI_str_utf8_invalid_strip(but->editstr, strlen(but->editstr)); /* not a file?, strip non utf-8 chars */ if (strip) { /* won't happen often so isn't that annoying to keep it here for a while */ diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index c9bfd883332..e13b69a9763 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -631,7 +631,7 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) case TH_NODE_SHADER: cp = ts->nodeclass_shader; break; - case TH_NODE_CONVERTOR: + case TH_NODE_CONVERTER: cp = ts->syntaxv; break; case TH_NODE_GROUP: diff --git a/source/blender/editors/interface/view2d_edge_pan.c b/source/blender/editors/interface/view2d_edge_pan.c index 1d300c7b275..eaf8ef30311 100644 --- a/source/blender/editors/interface/view2d_edge_pan.c +++ b/source/blender/editors/interface/view2d_edge_pan.c @@ -71,7 +71,8 @@ void UI_view2d_edge_pan_init(bContext *C, float outside_pad, float speed_ramp, float max_speed, - float delay) + float delay, + float zoom_influence) { if (!UI_view2d_edge_pan_poll(C)) { return; @@ -89,6 +90,7 @@ void UI_view2d_edge_pan_init(bContext *C, vpd->speed_ramp = speed_ramp; vpd->max_speed = max_speed; vpd->delay = delay; + vpd->zoom_influence = zoom_influence; /* Calculate translation factor, based on size of view. */ const float winx = (float)(BLI_rcti_size_x(&vpd->region->winrct) + 1); @@ -104,6 +106,7 @@ void UI_view2d_edge_pan_reset(View2DEdgePanData *vpd) vpd->edge_pan_start_time_x = 0.0; vpd->edge_pan_start_time_y = 0.0; vpd->edge_pan_last_time = PIL_check_seconds_timer(); + vpd->initial_rect = vpd->region->v2d.cur; } /** @@ -168,9 +171,15 @@ static float edge_pan_speed(View2DEdgePanData *vpd, /* Apply a fade in to the speed based on a start time delay. */ const double start_time = x_dir ? vpd->edge_pan_start_time_x : vpd->edge_pan_start_time_y; - const float delay_factor = smootherstep(vpd->delay, (float)(current_time - start_time)); + const float delay_factor = vpd->delay > 0.01f ? + smootherstep(vpd->delay, (float)(current_time - start_time)) : + 1.0f; - return distance_factor * delay_factor * vpd->max_speed * U.widget_unit * (float)U.dpi_fac; + /* Zoom factor increases speed when zooming in and decreases speed when zooming out. */ + const float zoomx = (float)(BLI_rcti_size_x(®ion->winrct) + 1) / BLI_rctf_size_x(®ion->v2d.cur); + const float zoom_factor = 1.0f + CLAMPIS(vpd->zoom_influence, 0.0f, 1.0f) * (zoomx - 1.0f); + + return distance_factor * delay_factor * zoom_factor * vpd->max_speed * U.widget_unit * (float)U.dpi_fac; } static void edge_pan_apply_delta(bContext *C, View2DEdgePanData *vpd, float dx, float dy) @@ -264,6 +273,27 @@ void UI_view2d_edge_pan_apply_event(bContext *C, View2DEdgePanData *vpd, const w UI_view2d_edge_pan_apply(C, vpd, event->x, event->y); } +void UI_view2d_edge_pan_cancel(bContext *C, View2DEdgePanData *vpd) +{ + View2D *v2d = vpd->v2d; + if (!v2d) { + return; + } + + v2d->cur = vpd->initial_rect; + + /* Inform v2d about changes after this operation. */ + UI_view2d_curRect_changed(C, v2d); + + /* Don't rebuild full tree in outliner, since we're just changing our view. */ + ED_region_tag_redraw_no_rebuild(vpd->region); + + /* Request updates to be done. */ + WM_event_add_mousemove(CTX_wm_window(C)); + + UI_view2d_sync(vpd->screen, vpd->area, v2d, V2D_LOCK_COPY); +} + void UI_view2d_edge_pan_operator_properties(wmOperatorType *ot) { /* Default values for edge panning operators. */ @@ -272,7 +302,8 @@ void UI_view2d_edge_pan_operator_properties(wmOperatorType *ot) /*outside_pad*/ 0.0f, /*speed_ramp*/ 1.0f, /*max_speed*/ 500.0f, - /*delay*/ 1.0f); + /*delay*/ 1.0f, + /*zoom_influence*/ 0.0f); } void UI_view2d_edge_pan_operator_properties_ex(struct wmOperatorType *ot, @@ -280,7 +311,8 @@ void UI_view2d_edge_pan_operator_properties_ex(struct wmOperatorType *ot, float outside_pad, float speed_ramp, float max_speed, - float delay) + float delay, + float zoom_influence) { RNA_def_float( ot->srna, @@ -329,6 +361,15 @@ void UI_view2d_edge_pan_operator_properties_ex(struct wmOperatorType *ot, "Delay in seconds before maximum speed is reached", 0.0f, 10.0f); + RNA_def_float(ot->srna, + "zoom_influence", + zoom_influence, + 0.0f, + 1.0f, + "Zoom Influence", + "Influence of the zoom factor on scroll speed", + 0.0f, + 1.0f); } void UI_view2d_edge_pan_operator_init(bContext *C, View2DEdgePanData *vpd, wmOperator *op) @@ -339,7 +380,8 @@ void UI_view2d_edge_pan_operator_init(bContext *C, View2DEdgePanData *vpd, wmOpe RNA_float_get(op->ptr, "outside_padding"), RNA_float_get(op->ptr, "speed_ramp"), RNA_float_get(op->ptr, "max_speed"), - RNA_float_get(op->ptr, "delay")); + RNA_float_get(op->ptr, "delay"), + RNA_float_get(op->ptr, "zoom_influence")); } /** \} */ diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 12b52907057..34400462d38 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -3359,8 +3359,13 @@ Base *ED_object_add_duplicate( Base *basen; Object *ob; - basen = object_add_duplicate_internal( - bmain, scene, view_layer, base->object, dupflag, LIB_ID_DUPLICATE_IS_SUBPROCESS); + basen = object_add_duplicate_internal(bmain, + scene, + view_layer, + base->object, + dupflag, + LIB_ID_DUPLICATE_IS_SUBPROCESS | + LIB_ID_DUPLICATE_IS_ROOT_ID); if (basen == NULL) { return NULL; } @@ -3395,8 +3400,13 @@ static int duplicate_exec(bContext *C, wmOperator *op) BKE_main_id_newptr_and_tag_clear(bmain); CTX_DATA_BEGIN (C, Base *, base, selected_bases) { - Base *basen = object_add_duplicate_internal( - bmain, scene, view_layer, base->object, dupflag, LIB_ID_DUPLICATE_IS_SUBPROCESS); + Base *basen = object_add_duplicate_internal(bmain, + scene, + view_layer, + base->object, + dupflag, + LIB_ID_DUPLICATE_IS_SUBPROCESS | + LIB_ID_DUPLICATE_IS_ROOT_ID); /* note that this is safe to do with this context iterator, * the list is made in advance */ @@ -3516,7 +3526,7 @@ static int object_add_named_exec(bContext *C, wmOperator *op) * the case here. So we have to do the new-ID relinking ourselves * (#copy_object_set_idnew()). */ - LIB_ID_DUPLICATE_IS_SUBPROCESS); + LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID); } else { /* basen is actually not a new base in this case. */ diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index e9142742d15..e1e0a0600be 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -352,7 +352,7 @@ static bool object_modifier_remove( /* special cases */ if (md->type == eModifierType_ParticleSystem) { - object_remove_particle_system(bmain, scene, ob); + object_remove_particle_system(bmain, scene, ob, ((ParticleSystemModifierData *)md)->psys); return true; } diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 2668846284d..3ac6dca3044 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -124,7 +124,8 @@ static int particle_system_remove_exec(bContext *C, wmOperator *UNUSED(op)) } mode_orig = ob->mode; - object_remove_particle_system(bmain, scene, ob); + ParticleSystem *psys = psys_get_current(ob); + object_remove_particle_system(bmain, scene, ob, psys); /* possible this isn't the active object * object_remove_particle_system() clears the mode on the last psys diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index c141789f171..798f4898aaa 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -198,7 +198,8 @@ static int file_browse_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); FileBrowseOp *fbo = op->customdata; ID *id; - char *str, path[FILE_MAX]; + char *str; + int str_len; const char *path_prop = RNA_struct_find_property(op->ptr, "directory") ? "directory" : "filepath"; @@ -206,10 +207,11 @@ static int file_browse_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - str = RNA_string_get_alloc(op->ptr, path_prop, NULL, 0); + str = RNA_string_get_alloc(op->ptr, path_prop, NULL, 0, &str_len); /* Add slash for directories, important for some properties. */ if (RNA_property_subtype(fbo->prop) == PROP_DIRPATH) { + char path[FILE_MAX]; const bool is_relative = RNA_boolean_get(op->ptr, "relative_path"); id = fbo->ptr.owner_id; @@ -220,13 +222,13 @@ static int file_browse_exec(bContext *C, wmOperator *op) /* Do this first so '//' isn't converted to '//\' on windows. */ BLI_path_slash_ensure(path); if (is_relative) { - BLI_strncpy(path, str, FILE_MAX); + const int path_len = BLI_strncpy_rlen(path, str, FILE_MAX); BLI_path_rel(path, BKE_main_blendfile_path(bmain)); - str = MEM_reallocN(str, strlen(path) + 2); + str = MEM_reallocN(str, path_len + 2); BLI_strncpy(str, path, FILE_MAX); } else { - str = MEM_reallocN(str, strlen(str) + 2); + str = MEM_reallocN(str, str_len + 2); } } else { diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c index bdb7c622cd2..763beb8671b 100644 --- a/source/blender/editors/space_console/console_ops.c +++ b/source/blender/editors/space_console/console_ops.c @@ -384,7 +384,7 @@ static int console_insert_exec(bContext *C, wmOperator *op) SpaceConsole *sc = CTX_wm_space_console(C); ARegion *region = CTX_wm_region(C); ConsoleLine *ci = console_history_verify(C); - char *str = RNA_string_get_alloc(op->ptr, "text", NULL, 0); + char *str = RNA_string_get_alloc(op->ptr, "text", NULL, 0, NULL); int len; if (str[0] == '\t' && str[1] == '\0') { @@ -860,7 +860,7 @@ static int console_history_append_exec(bContext *C, wmOperator *op) ScrArea *area = CTX_wm_area(C); ConsoleLine *ci = console_history_verify(C); /* own this text in the new line, don't free */ - char *str = RNA_string_get_alloc(op->ptr, "text", NULL, 0); + char *str = RNA_string_get_alloc(op->ptr, "text", NULL, 0, NULL); int cursor = RNA_int_get(op->ptr, "current_character"); const bool rem_dupes = RNA_boolean_get(op->ptr, "remove_duplicates"); int prev_len = ci->len; @@ -923,7 +923,7 @@ static int console_scrollback_append_exec(bContext *C, wmOperator *op) ConsoleLine *ci; /* own this text in the new line, don't free */ - char *str = RNA_string_get_alloc(op->ptr, "text", NULL, 0); + char *str = RNA_string_get_alloc(op->ptr, "text", NULL, 0, NULL); int type = RNA_enum_get(op->ptr, "type"); console_history_verify(C); diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c index 169dafcb8d0..a95189a303f 100644 --- a/source/blender/editors/space_image/image_edit.c +++ b/source/blender/editors/space_image/image_edit.c @@ -139,8 +139,10 @@ ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock, int tile) ImBuf *ibuf; if (sima && sima->image) { + const Image *image = sima->image; + #if 0 - if (sima->image->type == IMA_TYPE_R_RESULT && BIF_show_render_spare()) { + if (image->type == IMA_TYPE_R_RESULT && BIF_show_render_spare()) { return BIF_render_spare_imbuf(); } else @@ -152,6 +154,12 @@ ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock, int tile) } if (ibuf) { + if (image->type == IMA_TYPE_R_RESULT && ibuf->x != 0 && ibuf->y != 0) { + /* Render result might be lazily allocated. Return ibuf without buffers to indicate that + * there is image buffer but it has no data yet. */ + return ibuf; + } + if (ibuf->rect || ibuf->rect_float) { return ibuf; } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 29c1452b988..4f8feda3911 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -3935,7 +3935,7 @@ static int tile_add_exec(bContext *C, wmOperator *op) } bool fill_tile = RNA_boolean_get(op->ptr, "fill"); - char *label = RNA_string_get_alloc(op->ptr, "label", NULL, 0); + char *label = RNA_string_get_alloc(op->ptr, "label", NULL, 0, NULL); /* BKE_image_add_tile assumes a pre-sorted list of tiles. */ BKE_image_sort_tiles(ima); diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c index 288b3d94b1d..c4f111264a3 100644 --- a/source/blender/editors/space_image/image_sequence.c +++ b/source/blender/editors/space_image/image_sequence.c @@ -68,7 +68,7 @@ static void image_sequence_get_frame_ranges(wmOperator *op, ListBase *ranges) RNA_BEGIN (op->ptr, itemptr, "files") { char head[FILE_MAX], tail[FILE_MAX]; ushort digits; - char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0); + char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL); ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame"); /* use the first file in the list as base filename */ diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c index 94e53958524..a99396ecdf0 100644 --- a/source/blender/editors/space_info/info_ops.c +++ b/source/blender/editors/space_info/info_ops.c @@ -512,7 +512,7 @@ void FILE_OT_report_missing_files(wmOperatorType *ot) static int find_missing_files_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - const char *searchpath = RNA_string_get_alloc(op->ptr, "directory", NULL, 0); + const char *searchpath = RNA_string_get_alloc(op->ptr, "directory", NULL, 0, NULL); const bool find_all = RNA_boolean_get(op->ptr, "find_all"); BKE_bpath_missing_files_find(bmain, searchpath, op->reports, find_all); diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index 6ec6315a238..3b1a55f55ab 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -670,8 +670,8 @@ int node_get_colorid(bNode *node) return TH_NODE_INPUT; case NODE_CLASS_OUTPUT: return (node->flag & NODE_DO_OUTPUT) ? TH_NODE_OUTPUT : TH_NODE; - case NODE_CLASS_CONVERTOR: - return TH_NODE_CONVERTOR; + case NODE_CLASS_CONVERTER: + return TH_NODE_CONVERTER; case NODE_CLASS_OP_COLOR: return TH_NODE_COLOR; case NODE_CLASS_OP_VECTOR: diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc index a6901c21862..411719cf6c0 100644 --- a/source/blender/editors/space_node/node_geometry_attribute_search.cc +++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc @@ -17,6 +17,7 @@ #include "BLI_index_range.hh" #include "BLI_listbase.h" #include "BLI_map.hh" +#include "BLI_rect.h" #include "BLI_set.hh" #include "BLI_string_ref.hh" #include "BLI_string_search.h" diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index c6c3ca27d6e..e908a61eed9 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -880,6 +880,8 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) bNodeTree *ntree = snode->edittree; bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata; bool do_tag_update = false; + /* View will be reset if no links connect. */ + bool reset_view = true; /* avoid updates while applying links */ ntree->is_updating = true; @@ -917,6 +919,8 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) if (link->tonode) { do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, link->tonode)); } + + reset_view = false; } else { nodeRemLink(ntree, link); @@ -930,6 +934,10 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) snode_dag_update(C, snode); } + if (reset_view) { + UI_view2d_edge_pan_cancel(C, &nldrag->pan_data); + } + BLI_remlink(&snode->runtime->linkdrag, nldrag); /* links->data pointers are either held by the tree or freed already */ BLI_freelistN(&nldrag->links); @@ -1207,6 +1215,8 @@ static void node_link_cancel(bContext *C, wmOperator *op) BLI_remlink(&snode->runtime->linkdrag, nldrag); + UI_view2d_edge_pan_cancel(C, &nldrag->pan_data); + BLI_freelistN(&nldrag->links); MEM_freeN(nldrag); clear_picking_highlight(&snode->edittree->links); @@ -1258,7 +1268,8 @@ void NODE_OT_link(wmOperatorType *ot) NODE_EDGE_PAN_OUTSIDE_PAD, NODE_EDGE_PAN_SPEED_RAMP, NODE_EDGE_PAN_MAX_SPEED, - NODE_EDGE_PAN_DELAY); + NODE_EDGE_PAN_DELAY, + NODE_EDGE_PAN_ZOOM_INFLUENCE); } /** \} */ diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 1ec1afe86fc..ff0bd533671 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -625,7 +625,7 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op) } const eDupli_ID_Flags dupli_flags = USER_DUP_OBJECT | (linked ? 0 : U.dupflag); - BKE_collection_duplicate(bmain, parent, collection, dupli_flags, 0); + BKE_collection_duplicate(bmain, parent, collection, dupli_flags, LIB_ID_DUPLICATE_IS_ROOT_ID); DEG_relations_tag_update(bmain); WM_main_add_notifier(NC_SCENE | ND_LAYER, CTX_data_scene(C)); diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c index 50cfa2e71c7..13adf6bfc2d 100644 --- a/source/blender/editors/space_script/script_edit.c +++ b/source/blender/editors/space_script/script_edit.c @@ -47,12 +47,14 @@ static int run_pyfile_exec(bContext *C, wmOperator *op) { - char path[512]; + char path[FILE_MAX]; RNA_string_get(op->ptr, "filepath", path); #ifdef WITH_PYTHON if (BPY_run_filepath(C, path, op->reports)) { ARegion *region = CTX_wm_region(C); - ED_region_tag_redraw(region); + if (region != NULL) { + ED_region_tag_redraw(region); + } return OPERATOR_FINISHED; } #else @@ -70,7 +72,6 @@ void SCRIPT_OT_python_file_run(wmOperatorType *ot) /* api callbacks */ ot->exec = run_pyfile_exec; - ot->poll = ED_operator_areaactive; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index ff8cbdb1a59..16b690dd6e4 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -254,11 +254,11 @@ static void load_data_init_from_operator(SeqLoadData *load_data, bContext *C, wm BLI_strncpy(load_data->name, BLI_path_basename(load_data->path), sizeof(load_data->name)); } else if ((prop = RNA_struct_find_property(op->ptr, "directory"))) { - char *directory = RNA_string_get_alloc(op->ptr, "directory", NULL, 0); + char *directory = RNA_string_get_alloc(op->ptr, "directory", NULL, 0, NULL); if ((prop = RNA_struct_find_property(op->ptr, "files"))) { RNA_PROP_BEGIN (op->ptr, itemptr, prop) { - char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0); + char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL); BLI_strncpy(load_data->name, filename, sizeof(load_data->name)); BLI_join_dirfile(load_data->path, sizeof(load_data->path), directory, filename); MEM_freeN(filename); @@ -944,7 +944,7 @@ int sequencer_image_seq_get_minmax_frame(wmOperator *op, RNA_BEGIN (op->ptr, itemptr, "files") { char *filename; int frame; - filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0); + filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL); if (filename) { if (BLI_path_frame_get(filename, &frame, &numdigits)) { @@ -973,7 +973,7 @@ void sequencer_image_seq_reserve_frames( { char *filename = NULL; RNA_BEGIN (op->ptr, itemptr, "files") { - filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0); + filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL); break; } RNA_END; @@ -1023,7 +1023,7 @@ static void sequencer_add_image_strip_load_files( else { size_t strip_frame = 0; RNA_BEGIN (op->ptr, itemptr, "files") { - char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0); + char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL); SEQ_add_image_load_file(seq, strip_frame, filename); MEM_freeN(filename); strip_frame++; diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index afad8999e88..694e5fbb41d 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -1446,9 +1446,14 @@ static int sequencer_split_exec(bContext *C, wmOperator *op) } if (ignore_selection || seq->flag & SELECT) { - if (SEQ_edit_strip_split(bmain, scene, ed->seqbasep, seq, split_frame, method) != NULL) { + const char *error_msg = NULL; + if (SEQ_edit_strip_split(bmain, scene, ed->seqbasep, seq, split_frame, method, &error_msg) != + NULL) { changed = true; } + if (error_msg != NULL) { + BKE_report(op->reports, RPT_ERROR, error_msg); + } } } @@ -2826,7 +2831,7 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op) } else { RNA_BEGIN (op->ptr, itemptr, "files") { - char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0); + char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL); BLI_strncpy(se->name, filename, sizeof(se->name)); MEM_freeN(filename); se++; diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c index a38ed12e53b..32e455f3ac9 100644 --- a/source/blender/editors/space_text/text_autocomplete.c +++ b/source/blender/editors/space_text/text_autocomplete.c @@ -177,13 +177,12 @@ static GHash *text_autocomplete_build(Text *text) i_pos = i_start; while ((i_start < linep->len) && (!text_check_identifier_nodigit_unicode( - BLI_str_utf8_as_unicode_and_size_safe(&linep->line[i_start], &i_pos)))) { + BLI_str_utf8_as_unicode_step(linep->line, linep->len, &i_pos)))) { i_start = i_pos; } i_pos = i_end = i_start; - while ((i_end < linep->len) && - (text_check_identifier_unicode( - BLI_str_utf8_as_unicode_and_size_safe(&linep->line[i_end], &i_pos)))) { + while ((i_end < linep->len) && (text_check_identifier_unicode(BLI_str_utf8_as_unicode_step( + linep->line, linep->len, &i_pos)))) { i_end = i_pos; } diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 2b78ecb245d..f480f60a2b9 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -3424,25 +3424,26 @@ static int text_insert_exec(bContext *C, wmOperator *op) SpaceText *st = CTX_wm_space_text(C); Text *text = CTX_data_edit_text(C); char *str; + int str_len; bool done = false; size_t i = 0; uint code; text_drawcache_tag_update(st, 0); - str = RNA_string_get_alloc(op->ptr, "text", NULL, 0); + str = RNA_string_get_alloc(op->ptr, "text", NULL, 0, &str_len); ED_text_undo_push_init(C); if (st && st->overwrite) { while (str[i]) { - code = BLI_str_utf8_as_unicode_step(str, &i); + code = BLI_str_utf8_as_unicode_step(str, str_len, &i); done |= txt_replace_char(text, code); } } else { while (str[i]) { - code = BLI_str_utf8_as_unicode_step(str, &i); + code = BLI_str_utf8_as_unicode_step(str, str_len, &i); done |= txt_add_char(text, code); } } diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 4069a72a8fc..7a83fb71c28 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1671,6 +1671,13 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } } + if ((prop = RNA_struct_find_property(op->ptr, "view2d_edge_pan")) && + RNA_property_is_set(op->ptr, prop)) { + if (RNA_property_boolean_get(op->ptr, prop)) { + options |= CTX_VIEW2D_EDGE_PAN; + } + } + t->options = options; t->mode = mode; diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 549ad770ac6..013c5faa54a 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -94,6 +94,8 @@ typedef enum { CTX_OBMODE_XFORM_OBDATA = (1 << 12), /** Transform object parents without moving their children. */ CTX_OBMODE_XFORM_SKIP_CHILDREN = (1 << 13), + /** Enable edge scrolling in 2D views */ + CTX_VIEW2D_EDGE_PAN = (1 << 14), } eTContext; /** #TransInfo.flag */ diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 094ae080de0..d756e2c90a6 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -1662,20 +1662,23 @@ void animrecord_check_state(TransInfo *t, struct Object *ob) } } -void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, const float inv_unit_scale) +void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, const float y_fac) { + float delta_x = td->loc[0] - td->iloc[0]; + float delta_y = (td->loc[1] - td->iloc[1]) * y_fac; + /* If the handles are to be moved too * (as side-effect of keyframes moving, to keep the general effect) * offset them by the same amount so that the general angles are maintained * (i.e. won't change while handles are free-to-roam and keyframes are snap-locked). */ if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) { - td2d->h1[0] = td2d->ih1[0] + td->loc[0] - td->iloc[0]; - td2d->h1[1] = td2d->ih1[1] + (td->loc[1] - td->iloc[1]) * inv_unit_scale; + td2d->h1[0] = td2d->ih1[0] + delta_x; + td2d->h1[1] = td2d->ih1[1] + delta_y; } if ((td->flag & TD_MOVEHANDLE2) && td2d->h2) { - td2d->h2[0] = td2d->ih2[0] + td->loc[0] - td->iloc[0]; - td2d->h2[1] = td2d->ih2[1] + (td->loc[1] - td->iloc[1]) * inv_unit_scale; + td2d->h2[0] = td2d->ih2[0] + delta_x; + td2d->h2[1] = td2d->ih2[1] + delta_y; } } diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index fa34e2555d6..9cb0400cad9 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -43,9 +43,7 @@ void sort_trans_data_dist(TransInfo *t); void createTransData(struct bContext *C, TransInfo *t); bool clipUVTransform(TransInfo *t, float vec[2], const bool resize); void clipUVData(TransInfo *t); -void transform_convert_flush_handle2D(TransData *td, - TransData2D *td2d, - const float inv_unit_scale); +void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, const float y_fac); void recalcData(TransInfo *t); /* transform_convert_mesh.c */ diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c index a5565b5fb88..075db30fa61 100644 --- a/source/blender/editors/transform/transform_convert_action.c +++ b/source/blender/editors/transform/transform_convert_action.c @@ -158,8 +158,9 @@ static void TimeToTransData( /* Setup #TransData. */ td->loc = time; /* Usually #td2d->loc is used here. But this is for when the original location is not float[3]. */ + copy_v3_v3(td->iloc, td->loc); td->val = time; - td->ival = td->iloc[0] = *(time); + td->ival = *(time); td->center[0] = td->ival; td->center[1] = ypos; @@ -615,7 +616,11 @@ void recalcData_actedit(TransInfo *t) if ((autosnap != SACTSNAP_OFF) && (t->state != TRANS_CANCEL) && !(td->flag & TD_NOTIMESNAP)) { transform_snap_anim_flush_data(t, td, autosnap, td->loc); } - transform_convert_flush_handle2D(td, td2d, 1.0f); + + /* Constrain Y. */ + td->loc[1] = td->iloc[1]; + + transform_convert_flush_handle2D(td, td2d, 0.0f); } if (ac.datatype != ANIMCONT_MASK) { diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c index 9d2d3713bf0..ecc7f01be33 100644 --- a/source/blender/editors/transform/transform_convert_node.c +++ b/source/blender/editors/transform/transform_convert_node.c @@ -46,12 +46,6 @@ /** \name Node Transform Creation * \{ */ -typedef struct NodeTransCustomData { - /* Initial rect of the view2d, used for computing offset during edge panning */ - rctf initial_v2d_cur; - View2DEdgePanData edge_pan; -} NodeTransCustomData; - /* transcribe given node into TransData2D for Transforming */ static void NodeToTransData(TransData *td, TransData2D *td2d, bNode *node, const float dpi_fac) { @@ -115,21 +109,16 @@ void createTransNodeData(TransInfo *t) const float dpi_fac = UI_DPI_FAC; SpaceNode *snode = t->area->spacedata.first; - if (t->mode == TFM_TRANSLATION) { - /* Disable cursor wrapping in the node editor for edge pan */ - t->flag |= T_NO_CURSOR_WRAP; - } - /* Custom data to enable edge panning during the node transform */ - NodeTransCustomData *customdata = MEM_callocN(sizeof(*customdata), __func__); + View2DEdgePanData *customdata = MEM_callocN(sizeof(*customdata), __func__); UI_view2d_edge_pan_init(t->context, - &customdata->edge_pan, + customdata, NODE_EDGE_PAN_INSIDE_PAD, NODE_EDGE_PAN_OUTSIDE_PAD, NODE_EDGE_PAN_SPEED_RAMP, NODE_EDGE_PAN_MAX_SPEED, - NODE_EDGE_PAN_DELAY); - customdata->initial_v2d_cur = t->region->v2d.cur; + NODE_EDGE_PAN_DELAY, + NODE_EDGE_PAN_ZOOM_INFLUENCE); t->custom.type.data = customdata; t->custom.type.use_free = true; @@ -176,17 +165,22 @@ void flushTransNodes(TransInfo *t) { const float dpi_fac = UI_DPI_FAC; - NodeTransCustomData *customdata = (NodeTransCustomData *)t->custom.type.data; + View2DEdgePanData *customdata = (View2DEdgePanData *)t->custom.type.data; - if (t->mode == TFM_TRANSLATION) { - /* Edge panning functions expect window coordinates, mval is relative to region */ - const float x = t->region->winrct.xmin + t->mval[0]; - const float y = t->region->winrct.ymin + t->mval[1]; - UI_view2d_edge_pan_apply(t->context, &customdata->edge_pan, x, y); + if (t->options & CTX_VIEW2D_EDGE_PAN) { + if (t->state == TRANS_CANCEL) { + UI_view2d_edge_pan_cancel(t->context, customdata); + } + else { + /* Edge panning functions expect window coordinates, mval is relative to region */ + const float x = t->region->winrct.xmin + t->mval[0]; + const float y = t->region->winrct.ymin + t->mval[1]; + UI_view2d_edge_pan_apply(t->context, customdata, x, y); + } } /* Initial and current view2D rects for additional transform due to view panning and zooming */ - const rctf *rect_src = &customdata->initial_v2d_cur; + const rctf *rect_src = &customdata->initial_rect; const rctf *rect_dst = &t->region->v2d.cur; FOREACH_TRANS_DATA_CONTAINER (t, tc) { diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index 17512c79d03..45ed0f3b664 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -400,15 +400,14 @@ static void seq_transform_handle_overlap(TransInfo *t, SeqCollection *transforme if (seq_transform_check_strip_effects(transformed_strips)) { /* Update effect strips based on strips just moved in time. */ seq_transform_update_effects(t, transformed_strips); + } - /* If any effects still overlap, we need to move them up. */ - Sequence *seq; - SEQ_ITERATOR_FOREACH (seq, transformed_strips) { - if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) { - if (SEQ_transform_test_overlap(seqbasep, seq)) { - SEQ_transform_seqbase_shuffle(seqbasep, seq, t->scene); - } - } + /* If any effects still overlap, we need to move them up. + * In some cases other strips can be overlapping still, see T90646. */ + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, transformed_strips) { + if (SEQ_transform_test_overlap(seqbasep, seq)) { + SEQ_transform_seqbase_shuffle(seqbasep, seq, t->scene); } } } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 81fc1496b1a..9f5e74db501 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -625,6 +625,11 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } #endif + /* Disable cursor wrap when edge panning is enabled. */ + if (t->options & CTX_VIEW2D_EDGE_PAN) { + t->flag |= T_NO_CURSOR_WRAP; + } + setTransformViewAspect(t, t->aspect); if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) && diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 45c077b8a07..cbc2adf641f 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -709,6 +709,11 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) RNA_def_property_ui_text(prop, "Center Override", "Force using this center value (when set)"); } + if (flags & P_VIEW2D_EDGE_PAN) { + prop = RNA_def_boolean(ot->srna, "view2d_edge_pan", false, "Edge Pan", "Enable edge panning in 2D view"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + } + if ((flags & P_NO_DEFAULTS) == 0) { prop = RNA_def_boolean(ot->srna, "release_confirm", @@ -754,7 +759,8 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot) Transform_Properties(ot, P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | - P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT | P_POST_TRANSFORM); + P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT | P_VIEW2D_EDGE_PAN | + P_POST_TRANSFORM); } static void TRANSFORM_OT_resize(struct wmOperatorType *ot) diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c index 823837e2a42..d0eed6a6eb1 100644 --- a/source/blender/editors/util/numinput.c +++ b/source/blender/editors/util/numinput.c @@ -178,7 +178,7 @@ void outputNumInput(NumInput *n, char *str, UnitSettings *unit_settings) } /* We might have cut some multi-bytes utf8 chars * (e.g. trailing '°' of degrees values can become only 'A')... */ - BLI_utf8_invalid_strip(&str[j * ln], strlen(&str[j * ln])); + BLI_str_utf8_invalid_strip(&str[j * ln], strlen(&str[j * ln])); } } diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 99e3d59a57f..c71cde8ec43 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -1692,7 +1692,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu } if (obi->free_use_mesh) { - BKE_id_free(NULL, &obi->original_me); + BKE_id_free(NULL, obi->original_me); } if (rb->remove_doubles) { diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index fd794ed1b21..361fefa59d2 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1836,9 +1836,9 @@ typedef enum NodeShaderOutputTarget { /* Geometry Nodes */ typedef enum GeometryNodeAttributeProximityTargetType { - GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_POINTS = 0, - GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_EDGES = 1, - GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_FACES = 2, + GEO_NODE_PROXIMITY_TARGET_POINTS = 0, + GEO_NODE_PROXIMITY_TARGET_EDGES = 1, + GEO_NODE_PROXIMITY_TARGET_FACES = 2, } GeometryNodeAttributeProximityTargetType; typedef enum GeometryNodeBooleanOperation { diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index df18501d2ea..03c38eb71a0 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -339,11 +339,8 @@ typedef struct SpeedControlVars { float *frameMap; /* DEPRECATED, only used for versioning. */ float globalSpeed; - /* DEPRECATED, only used for versioning. */ int flags; - int length; - int lastValidFrame; int speed_control_type; float speed_fader; diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index f206bde4705..b943a8fad5a 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -1029,10 +1029,8 @@ void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *val void RNA_property_string_set_bytes(PointerRNA *ptr, PropertyRNA *prop, const char *value, int len); int RNA_property_string_length(PointerRNA *ptr, PropertyRNA *prop); void RNA_property_string_get_default(PointerRNA *ptr, PropertyRNA *prop, char *value); -char *RNA_property_string_get_default_alloc(PointerRNA *ptr, - PropertyRNA *prop, - char *fixedbuf, - int fixedlen); +char *RNA_property_string_get_default_alloc( + PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len); int RNA_property_string_default_length(PointerRNA *ptr, PropertyRNA *prop); int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop); @@ -1238,7 +1236,8 @@ bool RNA_enum_icon_from_value(const EnumPropertyItem *item, int value, int *r_ic bool RNA_enum_name_from_value(const EnumPropertyItem *item, int value, const char **r_name); void RNA_string_get(PointerRNA *ptr, const char *name, char *value); -char *RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen); +char *RNA_string_get_alloc( + PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len); int RNA_string_length(PointerRNA *ptr, const char *name); void RNA_string_set(PointerRNA *ptr, const char *name, const char *value); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 41c31dfebcb..c838032f1bb 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -3397,7 +3397,7 @@ char *RNA_property_string_get_alloc( buf = fixedbuf; } else { - buf = MEM_mallocN(sizeof(char) * (length + 1), "RNA_string_get_alloc"); + buf = MEM_mallocN(sizeof(char) * (length + 1), __func__); } #ifndef NDEBUG @@ -3537,10 +3537,8 @@ void RNA_property_string_get_default(PointerRNA *UNUSED(ptr), PropertyRNA *prop, strcpy(value, sprop->defaultvalue); } -char *RNA_property_string_get_default_alloc(PointerRNA *ptr, - PropertyRNA *prop, - char *fixedbuf, - int fixedlen) +char *RNA_property_string_get_default_alloc( + PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len) { char *buf; int length; @@ -3553,11 +3551,15 @@ char *RNA_property_string_get_default_alloc(PointerRNA *ptr, buf = fixedbuf; } else { - buf = MEM_callocN(sizeof(char) * (length + 1), "RNA_string_get_alloc"); + buf = MEM_callocN(sizeof(char) * (length + 1), __func__); } RNA_property_string_get_default(ptr, prop, buf); + if (r_len) { + *r_len = length; + } + return buf; } @@ -6587,15 +6589,18 @@ void RNA_string_get(PointerRNA *ptr, const char *name, char *value) } } -char *RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen) +char *RNA_string_get_alloc( + PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len) { PropertyRNA *prop = RNA_struct_find_property(ptr, name); if (prop) { - /* TODO: pass length. */ - return RNA_property_string_get_alloc(ptr, prop, fixedbuf, fixedlen, NULL); + return RNA_property_string_get_alloc(ptr, prop, fixedbuf, fixedlen, r_len); } printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name); + if (r_len != NULL) { + *r_len = 0; + } return NULL; } @@ -8166,7 +8171,7 @@ bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index) } case PROP_STRING: { - char *value = RNA_property_string_get_default_alloc(ptr, prop, NULL, 0); + char *value = RNA_property_string_get_default_alloc(ptr, prop, NULL, 0, NULL); RNA_property_string_set(ptr, prop, value); MEM_freeN(value); return true; diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index 9faf2ae7cb7..5f198a8ed4c 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -701,11 +701,7 @@ static float rna_CurveMapping_evaluateF(struct CurveMapping *cumap, } if (!cuma->table) { - BKE_report( - reports, - RPT_ERROR, - "CurveMap table not initialized, call initialize() on CurveMapping owner of the CurveMap"); - return 0.0f; + BKE_curvemapping_init(cumap); } return BKE_curvemap_evaluateF(cumap, cuma, value); } diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 8e6ff961721..9a33849b645 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -122,7 +122,7 @@ static void rna_idname_validate(const char *name, char *r_name) { BLI_strncpy(r_name, name, MAX_ID_NAME - 2); - BLI_utf8_invalid_strip(r_name, strlen(r_name)); + BLI_str_utf8_invalid_strip(r_name, strlen(r_name)); } static void rna_Main_ID_remove(Main *bmain, diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index d8ab7c7a61b..8d672e9b570 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -9853,17 +9853,17 @@ static void def_geo_collection_info(StructRNA *srna) static void def_geo_attribute_proximity(StructRNA *srna) { static const EnumPropertyItem target_geometry_element[] = { - {GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_POINTS, + {GEO_NODE_PROXIMITY_TARGET_POINTS, "POINTS", ICON_NONE, "Points", "Calculate proximity to the target's points (usually faster than the other two modes)"}, - {GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_EDGES, + {GEO_NODE_PROXIMITY_TARGET_EDGES, "EDGES", ICON_NONE, "Edges", "Calculate proximity to the target's edges"}, - {GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_FACES, + {GEO_NODE_PROXIMITY_TARGET_FACES, "FACES", ICON_NONE, "Faces", @@ -9877,7 +9877,7 @@ static void def_geo_attribute_proximity(StructRNA *srna) prop = RNA_def_property(srna, "target_geometry_element", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, target_geometry_element); - RNA_def_property_enum_default(prop, GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_FACES); + RNA_def_property_enum_default(prop, GEO_NODE_PROXIMITY_TARGET_FACES); RNA_def_property_ui_text( prop, "Target Geometry", "Element of the target geometry to calculate the distance from"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index 264ccccd350..7ddbf450e6a 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -102,13 +102,18 @@ static void rna_Sequences_move_strip_to_meta( } static Sequence *rna_Sequence_split( - ID *id, Sequence *seq, Main *bmain, int frame, int split_method) + ID *id, Sequence *seq, Main *bmain, ReportList *reports, int frame, int split_method) { Scene *scene = (Scene *)id; Editing *ed = SEQ_editing_get(scene, false); ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq); - Sequence *r_seq = SEQ_edit_strip_split(bmain, scene, seqbase, seq, frame, split_method); + const char *error_msg = NULL; + Sequence *r_seq = SEQ_edit_strip_split( + bmain, scene, seqbase, seq, frame, split_method, &error_msg); + if (error_msg != NULL) { + BKE_report(reports, RPT_ERROR, error_msg); + } /* Update depsgraph. */ DEG_relations_tag_update(bmain); @@ -119,6 +124,14 @@ static Sequence *rna_Sequence_split( return r_seq; } +static Sequence *rna_Sequence_parent_meta(ID *id, Sequence *seq_self) +{ + Scene *scene = (Scene *)id; + Editing *ed = SEQ_editing_get(scene, false); + + return SEQ_find_metastrip_by_sequence(&ed->seqbase, NULL, seq_self); +} + static Sequence *rna_Sequences_new_clip(ID *id, ListBase *seqbase, Main *bmain, @@ -697,6 +710,13 @@ void RNA_api_sequence_strip(StructRNA *srna) "Meta to move the strip into"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + func = RNA_def_function(srna, "parent_meta", "rna_Sequence_parent_meta"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); + RNA_def_function_ui_description(func, "Parent meta"); + /* return type */ + parm = RNA_def_pointer(func, "sequence", "Sequence", "", "Parent Meta"); + RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "invalidate_cache", "rna_Sequence_invalidate_cache_rnafunc"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, @@ -705,7 +725,7 @@ void RNA_api_sequence_strip(StructRNA *srna) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); func = RNA_def_function(srna, "split", "rna_Sequence_split"); - RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); + RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID | FUNC_USE_MAIN); RNA_def_function_ui_description(func, "Split Sequence"); parm = RNA_def_int( func, "frame", 0, INT_MIN, INT_MAX, "", "Frame where to split the strip", INT_MIN, INT_MAX); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index b910648495b..21a3c087197 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -649,10 +649,9 @@ static void rna_Event_unicode_get(PointerRNA *ptr, char *value) size_t len = 0; if (event->utf8_buf[0]) { - BLI_str_utf8_as_unicode_and_size(event->utf8_buf, &len); - if (len > 0) { + if (BLI_str_utf8_as_unicode_step_or_error(event->utf8_buf, sizeof(event->utf8_buf), &len) != + BLI_UTF8_ERR) memcpy(value, event->utf8_buf, len); - } } value[len] = '\0'; diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index 9f86727ce0a..2c28e9710ef 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -72,7 +72,7 @@ static void requiredDataMask(Object *UNUSED(ob), CustomData_MeshMasks *r_cddata_masks) { /* ask for UV coordinates */ - r_cddata_masks->lmask |= CD_MLOOPUV; + r_cddata_masks->lmask |= CD_MASK_MLOOPUV; } static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c index d21e0938356..cc657d6f91d 100644 --- a/source/blender/nodes/composite/node_composite_tree.c +++ b/source/blender/nodes/composite/node_composite_tree.c @@ -67,7 +67,7 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa func(calldata, NODE_CLASS_OP_COLOR, N_("Color")); func(calldata, NODE_CLASS_OP_VECTOR, N_("Vector")); func(calldata, NODE_CLASS_OP_FILTER, N_("Filter")); - func(calldata, NODE_CLASS_CONVERTOR, N_("Convertor")); + func(calldata, NODE_CLASS_CONVERTER, N_("Converter")); func(calldata, NODE_CLASS_MATTE, N_("Matte")); func(calldata, NODE_CLASS_DISTORT, N_("Distort")); func(calldata, NODE_CLASS_GROUP, N_("Group")); diff --git a/source/blender/nodes/composite/nodes/node_composite_idMask.c b/source/blender/nodes/composite/nodes/node_composite_idMask.c index a81dce10284..84563e7560b 100644 --- a/source/blender/nodes/composite/nodes/node_composite_idMask.c +++ b/source/blender/nodes/composite/nodes/node_composite_idMask.c @@ -38,7 +38,7 @@ void register_node_type_cmp_idmask(void) { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_ID_MASK, "ID Mask", NODE_CLASS_CONVERTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_ID_MASK, "ID Mask", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, cmp_node_idmask_in, cmp_node_idmask_out); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_math.c b/source/blender/nodes/composite/nodes/node_composite_math.c index c2982964a9f..2191c6bcdc3 100644 --- a/source/blender/nodes/composite/nodes/node_composite_math.c +++ b/source/blender/nodes/composite/nodes/node_composite_math.c @@ -36,7 +36,7 @@ void register_node_type_cmp_math(void) { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, cmp_node_math_in, cmp_node_math_out); node_type_label(&ntype, node_math_label); node_type_update(&ntype, node_math_update); diff --git a/source/blender/nodes/composite/nodes/node_composite_premulkey.c b/source/blender/nodes/composite/nodes/node_composite_premulkey.c index b5dc15a2789..be76bbf01cf 100644 --- a/source/blender/nodes/composite/nodes/node_composite_premulkey.c +++ b/source/blender/nodes/composite/nodes/node_composite_premulkey.c @@ -38,7 +38,7 @@ void register_node_type_cmp_premulkey(void) { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_PREMULKEY, "Alpha Convert", NODE_CLASS_CONVERTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_PREMULKEY, "Alpha Convert", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, cmp_node_premulkey_in, cmp_node_premulkey_out); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.c b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.c index 03d27caa701..001b197e23a 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.c +++ b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.c @@ -40,7 +40,7 @@ void register_node_type_cmp_sephsva(void) { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA, "Separate HSVA", NODE_CLASS_CONVERTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA, "Separate HSVA", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, cmp_node_sephsva_in, cmp_node_sephsva_out); nodeRegisterType(&ntype); @@ -63,7 +63,7 @@ void register_node_type_cmp_combhsva(void) { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA, "Combine HSVA", NODE_CLASS_CONVERTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA, "Combine HSVA", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, cmp_node_combhsva_in, cmp_node_combhsva_out); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.c b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.c index ee8d6b0c186..e08f27db254 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.c +++ b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.c @@ -40,7 +40,7 @@ void register_node_type_cmp_seprgba(void) { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA, "Separate RGBA", NODE_CLASS_CONVERTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA, "Separate RGBA", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, cmp_node_seprgba_in, cmp_node_seprgba_out); nodeRegisterType(&ntype); @@ -63,7 +63,7 @@ void register_node_type_cmp_combrgba(void) { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA, "Combine RGBA", NODE_CLASS_CONVERTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA, "Combine RGBA", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, cmp_node_combrgba_in, cmp_node_combrgba_out); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.c b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.c index a4aa6e4bf77..b3884296600 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.c +++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.c @@ -43,7 +43,7 @@ void register_node_type_cmp_sepycca(void) { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA, "Separate YCbCrA", NODE_CLASS_CONVERTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA, "Separate YCbCrA", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, cmp_node_sepycca_in, cmp_node_sepycca_out); node_type_init(&ntype, node_composit_init_mode_sepycca); @@ -72,7 +72,7 @@ void register_node_type_cmp_combycca(void) { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA, "Combine YCbCrA", NODE_CLASS_CONVERTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA, "Combine YCbCrA", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, cmp_node_combycca_in, cmp_node_combycca_out); node_type_init(&ntype, node_composit_init_mode_combycca); diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.c b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.c index 6c416b4f485..4da79ec7981 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.c +++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.c @@ -38,7 +38,7 @@ void register_node_type_cmp_sepyuva(void) { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA, "Separate YUVA", NODE_CLASS_CONVERTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA, "Separate YUVA", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, cmp_node_sepyuva_in, cmp_node_sepyuva_out); nodeRegisterType(&ntype); @@ -61,7 +61,7 @@ void register_node_type_cmp_combyuva(void) { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA, "Combine YUVA", NODE_CLASS_CONVERTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA, "Combine YUVA", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, cmp_node_combyuva_in, cmp_node_combyuva_out); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_setalpha.c b/source/blender/nodes/composite/nodes/node_composite_setalpha.c index 1488ff1a25f..1b44cc011e9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_setalpha.c +++ b/source/blender/nodes/composite/nodes/node_composite_setalpha.c @@ -45,7 +45,7 @@ void register_node_type_cmp_setalpha(void) { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SETALPHA, "Set Alpha", NODE_CLASS_CONVERTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_SETALPHA, "Set Alpha", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, cmp_node_setalpha_in, cmp_node_setalpha_out); node_type_init(&ntype, node_composit_init_setalpha); node_type_storage( diff --git a/source/blender/nodes/composite/nodes/node_composite_switchview.c b/source/blender/nodes/composite/nodes/node_composite_switchview.c index ec5c79cc087..b09d5119bc4 100644 --- a/source/blender/nodes/composite/nodes/node_composite_switchview.c +++ b/source/blender/nodes/composite/nodes/node_composite_switchview.c @@ -146,7 +146,7 @@ void register_node_type_cmp_switch_view(void) { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SWITCH_VIEW, "Switch View", NODE_CLASS_CONVERTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_SWITCH_VIEW, "Switch View", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, NULL, cmp_node_switch_view_out); ntype.initfunc_api = init_switch_view; diff --git a/source/blender/nodes/composite/nodes/node_composite_valToRgb.c b/source/blender/nodes/composite/nodes/node_composite_valToRgb.c index 0d46341b610..ed6dbfa2bf3 100644 --- a/source/blender/nodes/composite/nodes/node_composite_valToRgb.c +++ b/source/blender/nodes/composite/nodes/node_composite_valToRgb.c @@ -43,7 +43,7 @@ void register_node_type_cmp_valtorgb(void) { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, cmp_node_valtorgb_in, cmp_node_valtorgb_out); node_type_size(&ntype, 240, 200, 320); node_type_init(&ntype, node_composit_init_valtorgb); @@ -66,7 +66,7 @@ void register_node_type_cmp_rgbtobw(void) { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, cmp_node_rgbtobw_in, cmp_node_rgbtobw_out); node_type_size_preset(&ntype, NODE_SIZE_SMALL); diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc index 0ba9080918c..58e7d82beea 100644 --- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc +++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc @@ -90,7 +90,7 @@ void register_node_type_fn_boolean_math() { static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_BOOLEAN_MATH, "Boolean Math", NODE_CLASS_CONVERTOR, 0); + fn_node_type_base(&ntype, FN_NODE_BOOLEAN_MATH, "Boolean Math", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, fn_node_boolean_math_in, fn_node_boolean_math_out); node_type_label(&ntype, node_boolean_math_label); node_type_update(&ntype, node_boolean_math_update); diff --git a/source/blender/nodes/function/nodes/node_fn_float_compare.cc b/source/blender/nodes/function/nodes/node_fn_float_compare.cc index 16ffb761a15..918dd24e520 100644 --- a/source/blender/nodes/function/nodes/node_fn_float_compare.cc +++ b/source/blender/nodes/function/nodes/node_fn_float_compare.cc @@ -109,7 +109,7 @@ void register_node_type_fn_float_compare() { static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_FLOAT_COMPARE, "Float Compare", NODE_CLASS_CONVERTOR, 0); + fn_node_type_base(&ntype, FN_NODE_FLOAT_COMPARE, "Float Compare", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, fn_node_float_compare_in, fn_node_float_compare_out); node_type_label(&ntype, node_float_compare_label); node_type_update(&ntype, node_float_compare_update); diff --git a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc index 52acfefe615..40b8f27f895 100644 --- a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc +++ b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc @@ -87,7 +87,7 @@ void register_node_type_fn_float_to_int() { static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_FLOAT_TO_INT, "Float to Integer", NODE_CLASS_CONVERTOR, 0); + fn_node_type_base(&ntype, FN_NODE_FLOAT_TO_INT, "Float to Integer", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, fn_node_float_to_int_in, fn_node_float_to_int_out); node_type_label(&ntype, node_float_to_int_label); ntype.build_multi_function = fn_node_float_to_int_build_multi_function; diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc index 07a89a1fa8c..d6b23c38ee4 100644 --- a/source/blender/nodes/geometry/node_geometry_tree.cc +++ b/source/blender/nodes/geometry/node_geometry_tree.cc @@ -80,7 +80,7 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa func(calldata, NODE_CLASS_ATTRIBUTE, N_("Attribute")); func(calldata, NODE_CLASS_OP_COLOR, N_("Color")); func(calldata, NODE_CLASS_OP_VECTOR, N_("Vector")); - func(calldata, NODE_CLASS_CONVERTOR, N_("Convertor")); + func(calldata, NODE_CLASS_CONVERTER, N_("Converter")); func(calldata, NODE_CLASS_LAYOUT, N_("Layout")); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc index d71cb09f1bd..e94267cc936 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc @@ -53,8 +53,7 @@ static void geo_attribute_proximity_init(bNodeTree *UNUSED(ntree), bNode *node) NodeGeometryAttributeProximity *node_storage = (NodeGeometryAttributeProximity *)MEM_callocN( sizeof(NodeGeometryAttributeProximity), __func__); - node_storage->target_geometry_element = - GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_FACES; + node_storage->target_geometry_element = GEO_NODE_PROXIMITY_TARGET_FACES; node->storage = node_storage; } @@ -63,15 +62,10 @@ namespace blender::nodes { static void proximity_calc(MutableSpan<float> distance_span, MutableSpan<float3> location_span, const VArray<float3> &positions, - BVHTreeFromMesh &tree_data_mesh, - BVHTreeFromPointCloud &tree_data_pointcloud, - const bool bvh_mesh_success, - const bool bvh_pointcloud_success, - const bool store_distances, - const bool store_locations) + BVHTreeFromMesh *tree_data_mesh, + BVHTreeFromPointCloud *tree_data_pointcloud) { - IndexRange range = positions.index_range(); - threading::parallel_for(range, 512, [&](IndexRange range) { + threading::parallel_for(positions.index_range(), 512, [&](IndexRange range) { BVHTreeNearest nearest_from_mesh; BVHTreeNearest nearest_from_pointcloud; @@ -85,12 +79,12 @@ static void proximity_calc(MutableSpan<float> distance_span, /* Use the distance to the last found point as upper bound to speedup the bvh lookup. */ nearest_from_mesh.dist_sq = len_squared_v3v3(nearest_from_mesh.co, positions[i]); - if (bvh_mesh_success) { - BLI_bvhtree_find_nearest(tree_data_mesh.tree, + if (tree_data_mesh != nullptr) { + BLI_bvhtree_find_nearest(tree_data_mesh->tree, positions[i], &nearest_from_mesh, - tree_data_mesh.nearest_callback, - &tree_data_mesh); + tree_data_mesh->nearest_callback, + tree_data_mesh); } /* Use the distance to the closest point in the mesh to speedup the pointcloud bvh lookup. @@ -98,27 +92,27 @@ static void proximity_calc(MutableSpan<float> distance_span, * than the mesh. */ nearest_from_pointcloud.dist_sq = nearest_from_mesh.dist_sq; - if (bvh_pointcloud_success) { - BLI_bvhtree_find_nearest(tree_data_pointcloud.tree, + if (tree_data_pointcloud != nullptr) { + BLI_bvhtree_find_nearest(tree_data_pointcloud->tree, positions[i], &nearest_from_pointcloud, - tree_data_pointcloud.nearest_callback, - &tree_data_pointcloud); + tree_data_pointcloud->nearest_callback, + tree_data_pointcloud); } if (nearest_from_pointcloud.dist_sq < nearest_from_mesh.dist_sq) { - if (store_distances) { + if (!distance_span.is_empty()) { distance_span[i] = sqrtf(nearest_from_pointcloud.dist_sq); } - if (store_locations) { + if (!location_span.is_empty()) { location_span[i] = nearest_from_pointcloud.co; } } else { - if (store_distances) { + if (!distance_span.is_empty()) { distance_span[i] = sqrtf(nearest_from_mesh.dist_sq); } - if (store_locations) { + if (!location_span.is_empty()) { location_span[i] = nearest_from_mesh.co; } } @@ -132,13 +126,13 @@ static bool bvh_from_mesh(const Mesh *target_mesh, { BVHCacheType bvh_type = BVHTREE_FROM_LOOPTRI; switch (target_geometry_element) { - case GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_POINTS: + case GEO_NODE_PROXIMITY_TARGET_POINTS: bvh_type = BVHTREE_FROM_VERTS; break; - case GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_EDGES: + case GEO_NODE_PROXIMITY_TARGET_EDGES: bvh_type = BVHTREE_FROM_EDGES; break; - case GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_FACES: + case GEO_NODE_PROXIMITY_TARGET_FACES: bvh_type = BVHTREE_FROM_LOOPTRI; break; } @@ -181,23 +175,20 @@ static void attribute_calc_proximity(GeometryComponent &component, } BLI_assert(position_attribute.varray->type().is<float3>()); - const bNode &node = params.node(); - const NodeGeometryAttributeProximity &storage = *(const NodeGeometryAttributeProximity *) - node.storage; + const NodeGeometryAttributeProximity &storage = + *(const NodeGeometryAttributeProximity *)params.node().storage; - BVHTreeFromMesh tree_data_mesh; - BVHTreeFromPointCloud tree_data_pointcloud; bool bvh_mesh_success = false; - bool bvh_pointcloud_success = false; - + BVHTreeFromMesh tree_data_mesh; if (geometry_set_target.has_mesh()) { bvh_mesh_success = bvh_from_mesh( geometry_set_target.get_mesh_for_read(), storage.target_geometry_element, tree_data_mesh); } + bool bvh_pointcloud_success = false; + BVHTreeFromPointCloud tree_data_pointcloud; if (geometry_set_target.has_pointcloud() && - storage.target_geometry_element == - GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_POINTS) { + storage.target_geometry_element == GEO_NODE_PROXIMITY_TARGET_POINTS) { bvh_pointcloud_success = bvh_from_pointcloud(geometry_set_target.get_pointcloud_for_read(), tree_data_pointcloud); } @@ -211,12 +202,8 @@ static void attribute_calc_proximity(GeometryComponent &component, proximity_calc(distance_span, location_span, positions, - tree_data_mesh, - tree_data_pointcloud, - bvh_mesh_success, - bvh_pointcloud_success, - distance_attribute, /* Boolean. */ - location_attribute); /* Boolean. */ + bvh_mesh_success ? &tree_data_mesh : nullptr, + bvh_pointcloud_success ? &tree_data_pointcloud : nullptr); if (bvh_mesh_success) { free_bvhtree_from_mesh(&tree_data_mesh); diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc index 0aa5c68aaf5..c9ce2de1ea1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc @@ -179,7 +179,7 @@ void register_node_type_geo_switch() { static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTOR, 0); + geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, geo_node_switch_in, geo_node_switch_out); node_type_init(&ntype, geo_node_switch_init); node_type_update(&ntype, blender::nodes::geo_node_switch_update); diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index 98edc133a1d..c3a675fcd20 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -130,7 +130,7 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa func(calldata, NODE_CLASS_TEXTURE, N_("Texture")); func(calldata, NODE_CLASS_OP_COLOR, N_("Color")); func(calldata, NODE_CLASS_OP_VECTOR, N_("Vector")); - func(calldata, NODE_CLASS_CONVERTOR, N_("Convertor")); + func(calldata, NODE_CLASS_CONVERTER, N_("Converter")); func(calldata, NODE_CLASS_SCRIPT, N_("Script")); func(calldata, NODE_CLASS_GROUP, N_("Group")); func(calldata, NODE_CLASS_INTERFACE, N_("Interface")); diff --git a/source/blender/nodes/shader/nodes/node_shader_blackbody.c b/source/blender/nodes/shader/nodes/node_shader_blackbody.c index c946a76ab51..95c35affc27 100644 --- a/source/blender/nodes/shader/nodes/node_shader_blackbody.c +++ b/source/blender/nodes/shader/nodes/node_shader_blackbody.c @@ -52,7 +52,7 @@ void register_node_type_sh_blackbody(void) { static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_BLACKBODY, "Blackbody", NODE_CLASS_CONVERTOR, 0); + sh_node_type_base(&ntype, SH_NODE_BLACKBODY, "Blackbody", NODE_CLASS_CONVERTER, 0); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_socket_templates(&ntype, sh_node_blackbody_in, sh_node_blackbody_out); node_type_init(&ntype, NULL); diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.cc b/source/blender/nodes/shader/nodes/node_shader_clamp.cc index f105f8bcaf9..b90397e4892 100644 --- a/source/blender/nodes/shader/nodes/node_shader_clamp.cc +++ b/source/blender/nodes/shader/nodes/node_shader_clamp.cc @@ -78,7 +78,7 @@ void register_node_type_sh_clamp(void) { static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTOR, 0); + sh_fn_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, sh_node_clamp_in, sh_node_clamp_out); node_type_init(&ntype, node_shader_init_clamp); node_type_gpu(&ntype, gpu_shader_clamp); diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc index e4739e2864d..f48e824ccb5 100644 --- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc +++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc @@ -310,7 +310,7 @@ void register_node_type_sh_map_range(void) { static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTOR, 0); + sh_fn_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, sh_node_map_range_in, sh_node_map_range_out); node_type_init(&ntype, node_shader_init_map_range); node_type_update(&ntype, node_shader_update_map_range); diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index c30f2948ab1..66c50b6de46 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -152,7 +152,7 @@ void register_node_type_sh_math(void) { static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, 0); + sh_fn_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, sh_node_math_in, sh_node_math_out); node_type_label(&ntype, node_math_label); node_type_gpu(&ntype, gpu_shader_math); diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c b/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c index 951755be4f3..dfecb830b35 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c +++ b/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c @@ -61,7 +61,7 @@ void register_node_type_sh_sephsv(void) { static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTOR, 0); + sh_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, sh_node_sephsv_in, sh_node_sephsv_out); node_type_exec(&ntype, NULL, NULL, node_shader_exec_sephsv); node_type_gpu(&ntype, gpu_shader_sephsv); @@ -109,7 +109,7 @@ void register_node_type_sh_combhsv(void) { static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTOR, 0); + sh_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, sh_node_combhsv_in, sh_node_combhsv_out); node_type_exec(&ntype, NULL, NULL, node_shader_exec_combhsv); node_type_gpu(&ntype, gpu_shader_combhsv); diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc index 2779fc6bf68..d9cbee33c0f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc @@ -106,7 +106,7 @@ void register_node_type_sh_seprgb(void) { static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTOR, 0); + sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, sh_node_seprgb_in, sh_node_seprgb_out); node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_seprgb); node_type_gpu(&ntype, gpu_shader_seprgb); @@ -165,7 +165,7 @@ void register_node_type_sh_combrgb(void) { static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTOR, 0); + sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, sh_node_combrgb_in, sh_node_combrgb_out); node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_combrgb); node_type_gpu(&ntype, gpu_shader_combrgb); diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc index 1fd794cdd0a..3048ed1e9fc 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc @@ -91,7 +91,7 @@ void register_node_type_sh_sepxyz(void) { static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTOR, 0); + sh_fn_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, sh_node_sepxyz_in, sh_node_sepxyz_out); node_type_gpu(&ntype, gpu_shader_sepxyz); ntype.build_multi_function = sh_node_sepxyz_build_multi_function; @@ -131,7 +131,7 @@ void register_node_type_sh_combxyz(void) { static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTOR, 0); + sh_fn_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, sh_node_combxyz_in, sh_node_combxyz_out); node_type_gpu(&ntype, gpu_shader_combxyz); ntype.build_multi_function = sh_node_combxyz_build_multi_function; diff --git a/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c b/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c index 4216207d643..25c30aa4081 100644 --- a/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c +++ b/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c @@ -50,7 +50,7 @@ void register_node_type_sh_shadertorgb(void) { static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_SHADERTORGB, "Shader to RGB", NODE_CLASS_CONVERTOR, 0); + sh_node_type_base(&ntype, SH_NODE_SHADERTORGB, "Shader to RGB", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, sh_node_shadertorgb_in, sh_node_shadertorgb_out); node_type_init(&ntype, NULL); node_type_storage(&ntype, "", NULL, NULL); diff --git a/source/blender/nodes/shader/nodes/node_shader_squeeze.c b/source/blender/nodes/shader/nodes/node_shader_squeeze.c index c7b6af3980a..ca7bdf41df9 100644 --- a/source/blender/nodes/shader/nodes/node_shader_squeeze.c +++ b/source/blender/nodes/shader/nodes/node_shader_squeeze.c @@ -61,7 +61,7 @@ void register_node_type_sh_squeeze(void) { static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_SQUEEZE, "Squeeze Value", NODE_CLASS_CONVERTOR, 0); + sh_node_type_base(&ntype, SH_NODE_SQUEEZE, "Squeeze Value", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, sh_node_squeeze_in, sh_node_squeeze_out); node_type_storage(&ntype, "", NULL, NULL); node_type_exec(&ntype, NULL, NULL, node_shader_exec_squeeze); diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc b/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc index 1bc42ab0cc6..62f6b38c79f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc @@ -175,7 +175,7 @@ void register_node_type_sh_valtorgb(void) { static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTOR, 0); + sh_fn_node_type_base(&ntype, SH_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, sh_node_valtorgb_in, sh_node_valtorgb_out); node_type_init(&ntype, node_shader_init_valtorgb); node_type_size_preset(&ntype, NODE_SIZE_LARGE); @@ -221,7 +221,7 @@ void register_node_type_sh_rgbtobw(void) { static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTOR, 0); + sh_node_type_base(&ntype, SH_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, sh_node_rgbtobw_in, sh_node_rgbtobw_out); node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_rgbtobw); node_type_gpu(&ntype, gpu_shader_rgbtobw); diff --git a/source/blender/nodes/shader/nodes/node_shader_wavelength.c b/source/blender/nodes/shader/nodes/node_shader_wavelength.c index 30f69557020..f978537ee85 100644 --- a/source/blender/nodes/shader/nodes/node_shader_wavelength.c +++ b/source/blender/nodes/shader/nodes/node_shader_wavelength.c @@ -62,7 +62,7 @@ void register_node_type_sh_wavelength(void) { static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_WAVELENGTH, "Wavelength", NODE_CLASS_CONVERTOR, 0); + sh_node_type_base(&ntype, SH_NODE_WAVELENGTH, "Wavelength", NODE_CLASS_CONVERTER, 0); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_socket_templates(&ntype, sh_node_wavelength_in, sh_node_wavelength_out); node_type_init(&ntype, NULL); diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c index f771b4934b2..7452007639c 100644 --- a/source/blender/nodes/texture/node_texture_tree.c +++ b/source/blender/nodes/texture/node_texture_tree.c @@ -101,7 +101,7 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa func(calldata, NODE_CLASS_OP_COLOR, N_("Color")); func(calldata, NODE_CLASS_PATTERN, N_("Patterns")); func(calldata, NODE_CLASS_TEXTURE, N_("Textures")); - func(calldata, NODE_CLASS_CONVERTOR, N_("Convertor")); + func(calldata, NODE_CLASS_CONVERTER, N_("Converter")); func(calldata, NODE_CLASS_DISTORT, N_("Distort")); func(calldata, NODE_CLASS_GROUP, N_("Group")); func(calldata, NODE_CLASS_INTERFACE, N_("Interface")); diff --git a/source/blender/nodes/texture/nodes/node_texture_distance.c b/source/blender/nodes/texture/nodes/node_texture_distance.c index 489318514e5..f7deac9ff4a 100644 --- a/source/blender/nodes/texture/nodes/node_texture_distance.c +++ b/source/blender/nodes/texture/nodes/node_texture_distance.c @@ -61,7 +61,7 @@ void register_node_type_tex_distance(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_DISTANCE, "Distance", NODE_CLASS_CONVERTOR, 0); + tex_node_type_base(&ntype, TEX_NODE_DISTANCE, "Distance", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, inputs, outputs); node_type_storage(&ntype, "", NULL, NULL); node_type_exec(&ntype, NULL, NULL, exec); diff --git a/source/blender/nodes/texture/nodes/node_texture_math.c b/source/blender/nodes/texture/nodes/node_texture_math.c index 53022c9e120..ab226a4dd38 100644 --- a/source/blender/nodes/texture/nodes/node_texture_math.c +++ b/source/blender/nodes/texture/nodes/node_texture_math.c @@ -335,7 +335,7 @@ void register_node_type_tex_math(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, 0); + tex_node_type_base(&ntype, TEX_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, inputs, outputs); node_type_label(&ntype, node_math_label); node_type_storage(&ntype, "", NULL, NULL); diff --git a/source/blender/nodes/texture/nodes/node_texture_valToNor.c b/source/blender/nodes/texture/nodes/node_texture_valToNor.c index 2fb04777848..5ccd44b8bf0 100644 --- a/source/blender/nodes/texture/nodes/node_texture_valToNor.c +++ b/source/blender/nodes/texture/nodes/node_texture_valToNor.c @@ -80,7 +80,7 @@ void register_node_type_tex_valtonor(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_VALTONOR, "Value to Normal", NODE_CLASS_CONVERTOR, 0); + tex_node_type_base(&ntype, TEX_NODE_VALTONOR, "Value to Normal", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); diff --git a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c index 8d365e13fc4..2446ef05e0c 100644 --- a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c +++ b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c @@ -63,7 +63,7 @@ void register_node_type_tex_valtorgb(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTOR, 0); + tex_node_type_base(&ntype, TEX_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, valtorgb_in, valtorgb_out); node_type_size_preset(&ntype, NODE_SIZE_LARGE); node_type_init(&ntype, valtorgb_init); @@ -105,7 +105,7 @@ void register_node_type_tex_rgbtobw(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTOR, 0); + tex_node_type_base(&ntype, TEX_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER, 0); node_type_socket_templates(&ntype, rgbtobw_in, rgbtobw_out); node_type_exec(&ntype, NULL, NULL, rgbtobw_exec); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index ac1a7f68885..e9d5ae278bb 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -7774,7 +7774,7 @@ void BPY_rna_exit(void) * will crash giving a useful error with address sanitizer. The likely cause * for this list not being empty is a missing call to: #BKE_libblock_free_data_py. */ const int id_weakref_pool_len = BLI_ghash_len(id_weakref_pool); - if (id_weakref_pool_len != id_weakref_pool_len) { + if (id_weakref_pool_len != 0) { printf("Found %d unreleased ID's\n", id_weakref_pool_len); GHashIterator gh_iter; GHASH_ITER (gh_iter, id_weakref_pool) { diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h index 4534c86f7f7..cd839385bfb 100644 --- a/source/blender/render/RE_pipeline.h +++ b/source/blender/render/RE_pipeline.h @@ -155,6 +155,8 @@ typedef struct RenderResult { char *error; struct StampData *stamp_data; + + bool passes_allocated; } RenderResult; typedef struct RenderStats { diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c index 75b3f2db249..1510587502b 100644 --- a/source/blender/render/intern/engine.c +++ b/source/blender/render/intern/engine.c @@ -212,6 +212,8 @@ static RenderResult *render_result_from_bake(RenderEngine *engine, int x, int y, RenderPass *primitive_pass = render_layer_add_pass(rr, rl, 4, "BakePrimitive", "", "RGBA"); RenderPass *differential_pass = render_layer_add_pass(rr, rl, 4, "BakeDifferential", "", "RGBA"); + render_result_passes_allocated_ensure(rr); + /* Fill render passes from bake pixel array, to be read by the render engine. */ for (int ty = 0; ty < h; ty++) { size_t offset = ty * w * 4; @@ -328,6 +330,7 @@ RenderResult *RE_engine_begin_result( /* can be NULL if we CLAMP the width or height to 0 */ if (result) { render_result_clone_passes(re, result, viewname); + render_result_passes_allocated_ensure(result); RenderPart *pa; @@ -400,6 +403,14 @@ void RE_engine_end_result( return; } + if (!re->result->passes_allocated) { + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + if (!re->result->passes_allocated) { + render_result_passes_allocated_ensure(re->result); + } + BLI_rw_mutex_unlock(&re->resultmutex); + } + /* merge. on break, don't merge in result for preview renders, looks nicer */ if (!highlight) { /* for exr tile render, detect tiles that are done */ diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c index 479ad9209f0..9ef52b4bf41 100644 --- a/source/blender/render/intern/pipeline.c +++ b/source/blender/render/intern/pipeline.c @@ -354,6 +354,7 @@ RenderResult *RE_AcquireResultWrite(Render *re) { if (re) { BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + render_result_passes_allocated_ensure(re->result); return re->result; } diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c index 091f5964291..c29ab342ed7 100644 --- a/source/blender/render/intern/render_result.c +++ b/source/blender/render/intern/render_result.c @@ -222,7 +222,6 @@ RenderPass *render_layer_add_pass(RenderResult *rr, { const int view_id = BLI_findstringindex(&rr->views, viewname, offsetof(RenderView, name)); RenderPass *rpass = MEM_callocN(sizeof(RenderPass), name); - size_t rectsize = ((size_t)rr->rectx) * rr->recty * channels; rpass->channels = channels; rpass->rectx = rl->rectx; @@ -249,33 +248,6 @@ RenderPass *render_layer_add_pass(RenderResult *rr, } } - /* Always allocate combined for display, in case of save buffers - * other passes are not allocated and only saved to the EXR file. */ - if (rl->exrhandle == NULL || STREQ(rpass->name, RE_PASSNAME_COMBINED)) { - float *rect; - int x; - - rpass->rect = MEM_callocN(sizeof(float) * rectsize, name); - if (rpass->rect == NULL) { - MEM_freeN(rpass); - return NULL; - } - - if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) { - /* initialize to max speed */ - rect = rpass->rect; - for (x = rectsize - 1; x >= 0; x--) { - rect[x] = PASS_VECTOR_MAX; - } - } - else if (STREQ(rpass->name, RE_PASSNAME_Z)) { - rect = rpass->rect; - for (x = rectsize - 1; x >= 0; x--) { - rect[x] = 10e10; - } - } - } - BLI_addtail(&rl->passes, rpass); return rpass; @@ -316,6 +288,8 @@ RenderResult *render_result_new( rr->do_exr_tile = true; } + rr->passes_allocated = false; + render_result_views_new(rr, &re->r); /* check renderdata for amount of layers */ @@ -484,6 +458,40 @@ RenderResult *render_result_new( return rr; } +void render_result_passes_allocated_ensure(RenderResult *rr) +{ + LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) { + LISTBASE_FOREACH (RenderPass *, rp, &rl->passes) { + if (rl->exrhandle != NULL && !STREQ(rp->name, RE_PASSNAME_COMBINED)) { + continue; + } + + if (rp->rect != NULL) { + continue; + } + + const size_t rectsize = ((size_t)rr->rectx) * rr->recty * rp->channels; + rp->rect = MEM_callocN(sizeof(float) * rectsize, rp->name); + + if (STREQ(rp->name, RE_PASSNAME_VECTOR)) { + /* initialize to max speed */ + float *rect = rp->rect; + for (int x = rectsize - 1; x >= 0; x--) { + rect[x] = PASS_VECTOR_MAX; + } + } + else if (STREQ(rp->name, RE_PASSNAME_Z)) { + float *rect = rp->rect; + for (int x = rectsize - 1; x >= 0; x--) { + rect[x] = 10e10; + } + } + } + } + + rr->passes_allocated = true; +} + void render_result_clone_passes(Render *re, RenderResult *rr, const char *viewname) { RenderLayer *rl; @@ -1243,6 +1251,7 @@ void render_result_exr_file_end(Render *re, RenderEngine *engine) render_result_free_list(&re->fullresult, re->result); re->result = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); re->result->stamp_data = stamp_data; + render_result_passes_allocated_ensure(re->result); BLI_rw_mutex_unlock(&re->resultmutex); LISTBASE_FOREACH (RenderLayer *, rl, &re->result->layers) { diff --git a/source/blender/render/intern/render_result.h b/source/blender/render/intern/render_result.h index 7732c113700..1fc64a4ea97 100644 --- a/source/blender/render/intern/render_result.h +++ b/source/blender/render/intern/render_result.h @@ -55,6 +55,8 @@ struct RenderResult *render_result_new(struct Render *re, const char *layername, const char *viewname); +void render_result_passes_allocated_ensure(struct RenderResult *rr); + struct RenderResult *render_result_new_from_exr( void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty); diff --git a/source/blender/sequencer/CMakeLists.txt b/source/blender/sequencer/CMakeLists.txt index e324bc8b407..f060e6ad69b 100644 --- a/source/blender/sequencer/CMakeLists.txt +++ b/source/blender/sequencer/CMakeLists.txt @@ -33,6 +33,7 @@ set(INC ../render ../windowmanager ../../../intern/atomic + ../../../intern/clog ../../../intern/guardedalloc # dna_type_offsets.h diff --git a/source/blender/sequencer/SEQ_edit.h b/source/blender/sequencer/SEQ_edit.h index 6d043dffe72..fbbf4bc53ea 100644 --- a/source/blender/sequencer/SEQ_edit.h +++ b/source/blender/sequencer/SEQ_edit.h @@ -53,7 +53,8 @@ struct Sequence *SEQ_edit_strip_split(struct Main *bmain, struct ListBase *seqbase, struct Sequence *seq, const int timeline_frame, - const eSeqSplitMethod method); + const eSeqSplitMethod method, + const char **r_error); bool SEQ_edit_remove_gaps(struct Scene *scene, struct ListBase *seqbase, const int initial_frame, diff --git a/source/blender/sequencer/SEQ_iterator.h b/source/blender/sequencer/SEQ_iterator.h index cb2091511a9..3ade7309f89 100644 --- a/source/blender/sequencer/SEQ_iterator.h +++ b/source/blender/sequencer/SEQ_iterator.h @@ -73,6 +73,7 @@ struct Sequence *SEQ_iterator_yield(SeqIterator *iterator); SeqCollection *SEQ_collection_create(const char *name); SeqCollection *SEQ_collection_duplicate(SeqCollection *collection); uint SEQ_collection_len(const SeqCollection *collection); +bool SEQ_collection_has_strip(const struct Sequence *seq, const SeqCollection *collection); bool SEQ_collection_append_strip(struct Sequence *seq, SeqCollection *data); bool SEQ_collection_remove_strip(struct Sequence *seq, SeqCollection *data); void SEQ_collection_free(SeqCollection *collection); diff --git a/source/blender/sequencer/SEQ_relations.h b/source/blender/sequencer/SEQ_relations.h index 366c1002e22..54e53193b48 100644 --- a/source/blender/sequencer/SEQ_relations.h +++ b/source/blender/sequencer/SEQ_relations.h @@ -65,6 +65,9 @@ void SEQ_cache_iterate( void *userdata, bool callback_init(void *userdata, size_t item_count), bool callback_iter(void *userdata, struct Sequence *seq, int timeline_frame, int cache_type)); +struct Sequence *SEQ_find_metastrip_by_sequence(ListBase *seqbase /* = ed->seqbase */, + struct Sequence *meta /* = NULL */, + struct Sequence *seq); #ifdef __cplusplus } #endif diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c index 3ca0555d9a5..d4adad9a34d 100644 --- a/source/blender/sequencer/intern/effects.c +++ b/source/blender/sequencer/intern/effects.c @@ -61,6 +61,7 @@ #include "SEQ_effects.h" #include "SEQ_proxy.h" +#include "SEQ_relations.h" #include "SEQ_render.h" #include "SEQ_utils.h" @@ -3023,7 +3024,7 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl if (!i) { Sequence *meta; - meta = seq_find_metastrip_by_sequence(&ed->seqbase, NULL, seq); + meta = SEQ_find_metastrip_by_sequence(&ed->seqbase, NULL, seq); if (meta) { i = do_adjustment_impl(context, meta, timeline_frame); @@ -3069,8 +3070,6 @@ static void init_speed_effect(Sequence *seq) seq->effectdata = MEM_callocN(sizeof(SpeedControlVars), "speedcontrolvars"); v = (SpeedControlVars *)seq->effectdata; - v->frameMap = NULL; - v->length = 0; v->speed_control_type = SEQ_SPEED_STRETCH; v->speed_fader = 1.0f; v->speed_fader_length = 0.0f; @@ -3080,9 +3079,7 @@ static void init_speed_effect(Sequence *seq) static void load_speed_effect(Sequence *seq) { SpeedControlVars *v = (SpeedControlVars *)seq->effectdata; - v->frameMap = NULL; - v->length = 0; } static int num_inputs_speed(void) @@ -3105,7 +3102,6 @@ static void copy_speed_effect(Sequence *dst, Sequence *src, const int UNUSED(fla dst->effectdata = MEM_dupallocN(src->effectdata); v = (SpeedControlVars *)dst->effectdata; v->frameMap = NULL; - v->length = 0; } static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1)) @@ -3127,164 +3123,114 @@ static int seq_effect_speed_get_strip_content_length(const Sequence *seq) return seq->len; } -void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool force) +static FCurve *seq_effect_speed_speed_factor_curve_get(Scene *scene, Sequence *seq) { - int timeline_frame; - float fallback_fac = 1.0f; - SpeedControlVars *v = (SpeedControlVars *)seq->effectdata; - FCurve *fcu = NULL; - - /* if not already done, load / initialize data */ - SEQ_effect_handle_get(seq); + return id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL); +} - if ((force == false) && (seq->len == v->length) && (v->frameMap != NULL)) { - return; - } +/* Build frame map when speed in mode #SEQ_SPEED_MULTIPLY is animated. + * This is, because `target_frame` value is integrated over time. */ +void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq) +{ if ((seq->seq1 == NULL) || (seq->len < 1)) { - /* make coverity happy and check for (CID 598) input strip ... */ - return; + return; /* Make coverity happy and check for (CID 598) input strip... */ } - /* XXX(campbell): new in 2.5x. should we use the animation system this way? - * The fcurve is needed because many frames need evaluating at once. */ - switch (v->speed_control_type) { - case SEQ_SPEED_MULTIPLY: { - fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL); - break; - } - case SEQ_SPEED_FRAME_NUMBER: { - fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_frame_number", 0, NULL); - break; - } - case SEQ_SPEED_LENGTH: { - fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_length", 0, NULL); - break; - } + FCurve *fcu = seq_effect_speed_speed_factor_curve_get(scene, seq); + if (fcu == NULL) { + return; } - if (!v->frameMap || v->length != seq->len) { - if (v->frameMap) { - MEM_freeN(v->frameMap); - } - - v->length = seq->len; - v->frameMap = MEM_callocN(sizeof(float) * v->length, "speedcontrol frameMap"); + SpeedControlVars *v = (SpeedControlVars *)seq->effectdata; + if (v->frameMap) { + MEM_freeN(v->frameMap); } - fallback_fac = 1.0; + const int effect_strip_length = seq->enddisp - seq->startdisp; + v->frameMap = MEM_mallocN(sizeof(float) * effect_strip_length, __func__); + v->frameMap[0] = 0.0f; - const int target_strip_length = seq_effect_speed_get_strip_content_length(seq->seq1); - - if (v->speed_control_type == SEQ_SPEED_STRETCH) { - if ((seq->seq1->enddisp != seq->seq1->start) && (target_strip_length != 0)) { - fallback_fac = (float)target_strip_length / (float)(seq->seq1->enddisp - seq->seq1->start); - fcu = NULL; - } - } - else { - /* if there is no fcurve, use value as simple multiplier */ - if (!fcu) { - switch (v->speed_control_type) { - case SEQ_SPEED_MULTIPLY: { - fallback_fac = v->speed_fader; - break; - } - case SEQ_SPEED_FRAME_NUMBER: { - fallback_fac = v->speed_fader_frame_number; - break; - } - case SEQ_SPEED_LENGTH: { - fallback_fac = v->speed_fader_length; - break; - } - } - } + float target_frame = 0; + for (int frame_index = 1; frame_index < effect_strip_length; frame_index++) { + target_frame += evaluate_fcurve(fcu, seq->startdisp + frame_index); + v->frameMap[frame_index] = target_frame; } +} - if (ELEM(v->speed_control_type, SEQ_SPEED_MULTIPLY, SEQ_SPEED_STRETCH)) { - float cursor = 0; - float facf; - - v->frameMap[0] = 0; - v->lastValidFrame = 0; - - for (timeline_frame = 1; timeline_frame < v->length; timeline_frame++) { - if (fcu) { - facf = evaluate_fcurve(fcu, seq->startdisp + timeline_frame); - } - else { - facf = fallback_fac; - } - - cursor += facf; - - if (cursor >= target_strip_length) { - v->frameMap[timeline_frame] = target_strip_length - 1; - } - else { - v->frameMap[timeline_frame] = cursor; - v->lastValidFrame = timeline_frame; - } - } +static void seq_effect_speed_frame_map_ensure(Scene *scene, Sequence *seq) +{ + SpeedControlVars *v = (SpeedControlVars *)seq->effectdata; + if (v->frameMap != NULL) { + return; } - else { - float facf; - v->lastValidFrame = 0; - for (timeline_frame = 0; timeline_frame < v->length; timeline_frame++) { + seq_effect_speed_rebuild_map(scene, seq); +} - if (fcu) { - facf = evaluate_fcurve(fcu, seq->startdisp + timeline_frame); - } - else { - facf = fallback_fac; - } +/* Override timeline_frame when rendering speed effect input. */ +float seq_speed_effect_target_frame_get(Scene *scene, + Sequence *seq_speed, + float timeline_frame, + int input) +{ + if (seq_speed->seq1 == NULL) { + return 0.0f; + } - if (v->speed_control_type == SEQ_SPEED_LENGTH) { - facf *= target_strip_length; - facf /= 100.0f; - } + SEQ_effect_handle_get(seq_speed); /* Ensure, that data are initialized. */ + int frame_index = seq_give_frame_index(seq_speed, timeline_frame); + SpeedControlVars *s = (SpeedControlVars *)seq_speed->effectdata; + const Sequence *source = seq_speed->seq1; - if (facf >= target_strip_length) { - facf = target_strip_length - 1; + float target_frame = 0.0f; + switch (s->speed_control_type) { + case SEQ_SPEED_STRETCH: { + const float target_content_length = seq_effect_speed_get_strip_content_length(source); + const float target_strip_length = source->enddisp - source->startdisp; + const float ratio = target_content_length / target_strip_length; + target_frame = frame_index * ratio; + break; + } + case SEQ_SPEED_MULTIPLY: { + FCurve *fcu = seq_effect_speed_speed_factor_curve_get(scene, seq_speed); + if (fcu != NULL) { + seq_effect_speed_frame_map_ensure(scene, seq_speed); + target_frame = s->frameMap[frame_index]; } else { - v->lastValidFrame = timeline_frame; + target_frame = frame_index * s->speed_fader; } - v->frameMap[timeline_frame] = facf; + break; } + case SEQ_SPEED_LENGTH: + target_frame = seq_effect_speed_get_strip_content_length(source) * + (s->speed_fader_length / 100.0f); + break; + case SEQ_SPEED_FRAME_NUMBER: + target_frame = s->speed_fader_frame_number; + break; } -} -/* Override timeline_frame when rendering speed effect input. */ -float seq_speed_effect_target_frame_get(const SeqRenderData *context, - Sequence *seq, - float timeline_frame, - int input) -{ - int frame_index = seq_give_frame_index(seq, timeline_frame); - SpeedControlVars *s = (SpeedControlVars *)seq->effectdata; - seq_effect_speed_rebuild_map(context->scene, seq, false); + CLAMP(target_frame, 0, seq_effect_speed_get_strip_content_length(source)); + target_frame += seq_speed->start; /* No interpolation. */ if ((s->flags & SEQ_SPEED_USE_INTERPOLATION) == 0) { - return seq->start + s->frameMap[frame_index]; + return target_frame; } - /* We need to provide current and next image for interpolation. */ - if (input == 0) { /* Current frame. */ - return floor(seq->start + s->frameMap[frame_index]); - } - /* Next frame. */ - return ceil(seq->start + s->frameMap[frame_index]); + /* Interpolation is used, switch between current and next frame based on which input is + * requested. */ + return input == 0 ? target_frame : ceil(target_frame); } -static float speed_effect_interpolation_ratio_get(SpeedControlVars *s, - Sequence *seq, +static float speed_effect_interpolation_ratio_get(Scene *scene, + Sequence *seq_speed, float timeline_frame) { - int frame_index = seq_give_frame_index(seq, timeline_frame); - return s->frameMap[frame_index] - floor(s->frameMap[frame_index]); + const float target_frame = seq_speed_effect_target_frame_get( + scene, seq_speed, timeline_frame, 0); + return target_frame - floor(target_frame); } static ImBuf *do_speed_effect(const SeqRenderData *context, @@ -3302,7 +3248,7 @@ static ImBuf *do_speed_effect(const SeqRenderData *context, if (s->flags & SEQ_SPEED_USE_INTERPOLATION) { out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3); - facf0 = facf1 = speed_effect_interpolation_ratio_get(s, seq, timeline_frame); + facf0 = facf1 = speed_effect_interpolation_ratio_get(context->scene, seq, timeline_frame); /* Current frame is ibuf1, next frame is ibuf2. */ out = seq_render_effect_execute_threaded( &cross_effect, context, NULL, timeline_frame, facf0, facf1, ibuf1, ibuf2, ibuf3); diff --git a/source/blender/sequencer/intern/effects.h b/source/blender/sequencer/intern/effects.h index 1bce4f324c3..25ba4d8956e 100644 --- a/source/blender/sequencer/intern/effects.h +++ b/source/blender/sequencer/intern/effects.h @@ -39,8 +39,8 @@ struct Sequence; */ struct SeqEffectHandle seq_effect_get_sequence_blend(struct Sequence *seq); -void seq_effect_speed_rebuild_map(struct Scene *scene, struct Sequence *seq, bool force); -float seq_speed_effect_target_frame_get(const struct SeqRenderData *context, +void seq_effect_speed_rebuild_map(struct Scene *scene, struct Sequence *seq); +float seq_speed_effect_target_frame_get(struct Scene *scene, struct Sequence *seq, float timeline_frame, int input); diff --git a/source/blender/sequencer/intern/iterator.c b/source/blender/sequencer/intern/iterator.c index 09f033e70fb..333a8e46c44 100644 --- a/source/blender/sequencer/intern/iterator.c +++ b/source/blender/sequencer/intern/iterator.c @@ -123,6 +123,14 @@ uint SEQ_collection_len(const SeqCollection *collection) } /** + * Check if seq is in collection. + */ +bool SEQ_collection_has_strip(const Sequence *seq, const SeqCollection *collection) +{ + return BLI_gset_haskey(collection->set, seq); +} + +/** * Query strips from seqbase. seq_reference is used by query function as filter condition. * * \param seq_reference: reference strip for query function diff --git a/source/blender/sequencer/intern/prefetch.c b/source/blender/sequencer/intern/prefetch.c index 15609a76f5c..dd2d828415c 100644 --- a/source/blender/sequencer/intern/prefetch.c +++ b/source/blender/sequencer/intern/prefetch.c @@ -53,7 +53,9 @@ #include "DEG_depsgraph_debug.h" #include "DEG_depsgraph_query.h" +#include "SEQ_iterator.h" #include "SEQ_prefetch.h" +#include "SEQ_relations.h" #include "SEQ_render.h" #include "SEQ_sequencer.h" @@ -359,67 +361,93 @@ void seq_prefetch_free(Scene *scene) scene->ed->prefetch_job = NULL; } -/* Skip frame if we need to render 3D scene strip. Rendering 3D scene requires main lock or setting - * up render job that doesn't have API to do openGL renders which can be used for sequencer. */ -static bool seq_prefetch_do_skip_frame(PrefetchJob *pfjob, ListBase *seqbase) +static bool seq_prefetch_seq_has_disk_cache(PrefetchJob *pfjob, + Sequence *seq, + bool can_have_final_image) { - float cfra = seq_prefetch_cfra(pfjob); - Sequence *seq_arr[MAXSEQ + 1]; - int count = seq_get_shown_sequences(seqbase, cfra, 0, seq_arr); SeqRenderData *ctx = &pfjob->context_cpy; - ImBuf *ibuf = NULL; + float cfra = seq_prefetch_cfra(pfjob); - /* Disable prefetching 3D scene strips, but check for disk cache. */ - for (int i = 0; i < count; i++) { - if (seq_arr[i]->type == SEQ_TYPE_META && - seq_prefetch_do_skip_frame(pfjob, &seq_arr[i]->seqbase)) { - return true; - } + ImBuf *ibuf = seq_cache_get(ctx, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED); + if (ibuf != NULL) { + IMB_freeImBuf(ibuf); + return true; + } - if (seq_arr[i]->type == SEQ_TYPE_SCENE && (seq_arr[i]->flag & SEQ_SCENE_STRIPS) == 0) { - int cached_types = 0; + ibuf = seq_cache_get(ctx, seq, cfra, SEQ_CACHE_STORE_RAW); + if (ibuf != NULL) { + IMB_freeImBuf(ibuf); + return true; + } - ibuf = seq_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_FINAL_OUT); - if (ibuf != NULL) { - cached_types |= SEQ_CACHE_STORE_FINAL_OUT; - IMB_freeImBuf(ibuf); - ibuf = NULL; - } + if (!can_have_final_image) { + return false; + } - ibuf = seq_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_COMPOSITE); - if (ibuf != NULL) { - cached_types |= SEQ_CACHE_STORE_COMPOSITE; - IMB_freeImBuf(ibuf); - ibuf = NULL; - } + ibuf = seq_cache_get(ctx, seq, cfra, SEQ_CACHE_STORE_FINAL_OUT); + if (ibuf != NULL) { + IMB_freeImBuf(ibuf); + return true; + } - ibuf = seq_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_PREPROCESSED); - if (ibuf != NULL) { - cached_types |= SEQ_CACHE_STORE_PREPROCESSED; - IMB_freeImBuf(ibuf); - ibuf = NULL; - } + return false; +} - ibuf = seq_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_RAW); - if (ibuf != NULL) { - cached_types |= SEQ_CACHE_STORE_RAW; - IMB_freeImBuf(ibuf); - ibuf = NULL; - } +static bool seq_prefetch_scene_strip_is_rendered(PrefetchJob *pfjob, + ListBase *seqbase, + SeqCollection *scene_strips, + bool is_recursive_check) +{ + float cfra = seq_prefetch_cfra(pfjob); + Sequence *seq_arr[MAXSEQ + 1]; + int count = seq_get_shown_sequences(seqbase, cfra, 0, seq_arr); - if ((cached_types & (SEQ_CACHE_STORE_RAW | SEQ_CACHE_STORE_PREPROCESSED)) != 0) { - continue; - } + /* Iterate over rendered strips. */ + for (int i = 0; i < count; i++) { + Sequence *seq = seq_arr[i]; + if (seq->type == SEQ_TYPE_META && + seq_prefetch_scene_strip_is_rendered(pfjob, &seq->seqbase, scene_strips, true)) { + return true; + } + + /* Disable prefetching 3D scene strips, but check for disk cache. */ + if (seq->type == SEQ_TYPE_SCENE && (seq->flag & SEQ_SCENE_STRIPS) == 0 && + !seq_prefetch_seq_has_disk_cache(pfjob, seq, !is_recursive_check)) { + return true; + } - /* It is only safe to use these cache types if strip is last in stack. */ - if (i == count - 1 && (cached_types & SEQ_CACHE_STORE_FINAL_OUT) != 0) { - continue; + /* Check if strip is effect of scene strip or uses it as modifier. This is recursive check. */ + Sequence *seq_scene; + SEQ_ITERATOR_FOREACH (seq_scene, scene_strips) { + if (SEQ_relations_render_loop_check(seq, seq_scene)) { + return true; } + } + } + return false; +} - return true; +static SeqCollection *query_scene_strips(ListBase *seqbase) +{ + SeqCollection *collection = SEQ_query_all_strips_recursive(seqbase); + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + if (seq->type != SEQ_TYPE_SCENE || (seq->flag & SEQ_SCENE_STRIPS) != 0) { + SEQ_collection_remove_strip(seq, collection); } } + return collection; +} +/* Prefetch must avoid rendering scene strips, because rendering in background locks UI and can + * make it unresponsive for long time periods. */ +static bool seq_prefetch_must_skip_frame(PrefetchJob *pfjob, ListBase *seqbase) +{ + SeqCollection *scene_strips = query_scene_strips(seqbase); + if (seq_prefetch_scene_strip_is_rendered(pfjob, seqbase, scene_strips, false)) { + SEQ_collection_free(scene_strips); + return true; + } + SEQ_collection_free(scene_strips); return false; } @@ -464,7 +492,7 @@ static void *seq_prefetch_frames(void *job) pfjob->scene_eval->ed->prefetch_job = pfjob; ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(pfjob->scene, false)); - if (seq_prefetch_do_skip_frame(pfjob, seqbase)) { + if (seq_prefetch_must_skip_frame(pfjob, seqbase)) { pfjob->num_frames_prefetched++; continue; } diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index aba84743621..0c07a25e2e2 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -840,7 +840,7 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, for (i = 0; i < 3; i++) { /* Speed effect requires time remapping of `timeline_frame` for input(s). */ if (input[0] && seq->type == SEQ_TYPE_SPEED) { - float target_frame = seq_speed_effect_target_frame_get(context, seq, timeline_frame, i); + float target_frame = seq_speed_effect_target_frame_get(scene, seq, timeline_frame, i); ibuf[i] = seq_render_strip(context, state, input[0], target_frame); } else { /* Other effects. */ diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c index e92afee08cd..17ff1c90be8 100644 --- a/source/blender/sequencer/intern/strip_edit.c +++ b/source/blender/sequencer/intern/strip_edit.c @@ -351,6 +351,11 @@ static void seq_split_set_left_offset(Sequence *seq, int timeline_frame) SEQ_transform_set_left_handle_frame(seq, timeline_frame); } +static bool seq_edit_split_effect_intersect_check(const Sequence *seq, const int timeline_frame) +{ + return timeline_frame > seq->startdisp && timeline_frame < seq->enddisp; +} + static void seq_edit_split_handle_strip_offsets(Main *bmain, Scene *scene, Sequence *left_seq, @@ -358,20 +363,82 @@ static void seq_edit_split_handle_strip_offsets(Main *bmain, const int timeline_frame, const eSeqSplitMethod method) { - switch (method) { - case SEQ_SPLIT_SOFT: - seq_split_set_left_offset(right_seq, timeline_frame); - seq_split_set_right_offset(left_seq, timeline_frame); - break; - case SEQ_SPLIT_HARD: - seq_split_set_right_hold_offset(left_seq, timeline_frame); - seq_split_set_left_hold_offset(right_seq, timeline_frame); - SEQ_add_reload_new_file(bmain, scene, left_seq, false); - SEQ_add_reload_new_file(bmain, scene, right_seq, false); - break; - } - SEQ_time_update_sequence(scene, left_seq); - SEQ_time_update_sequence(scene, right_seq); + if (seq_edit_split_effect_intersect_check(right_seq, timeline_frame)) { + switch (method) { + case SEQ_SPLIT_SOFT: + seq_split_set_left_offset(right_seq, timeline_frame); + break; + case SEQ_SPLIT_HARD: + seq_split_set_left_hold_offset(right_seq, timeline_frame); + SEQ_add_reload_new_file(bmain, scene, right_seq, false); + break; + } + SEQ_time_update_sequence(scene, right_seq); + } + + if (seq_edit_split_effect_intersect_check(left_seq, timeline_frame)) { + switch (method) { + case SEQ_SPLIT_SOFT: + seq_split_set_right_offset(left_seq, timeline_frame); + break; + case SEQ_SPLIT_HARD: + seq_split_set_right_hold_offset(left_seq, timeline_frame); + SEQ_add_reload_new_file(bmain, scene, left_seq, false); + break; + } + SEQ_time_update_sequence(scene, left_seq); + } +} + +static bool seq_edit_split_effect_inputs_intersect(const Sequence *seq, const int timeline_frame) +{ + bool input_does_intersect = false; + if (seq->seq1) { + input_does_intersect |= seq_edit_split_effect_intersect_check(seq->seq1, timeline_frame); + if ((seq->seq1->type & SEQ_TYPE_EFFECT) != 0) { + input_does_intersect |= seq_edit_split_effect_inputs_intersect(seq->seq1, timeline_frame); + } + } + if (seq->seq2) { + input_does_intersect |= seq_edit_split_effect_intersect_check(seq->seq2, timeline_frame); + if ((seq->seq1->type & SEQ_TYPE_EFFECT) != 0) { + input_does_intersect |= seq_edit_split_effect_inputs_intersect(seq->seq2, timeline_frame); + } + } + if (seq->seq3) { + input_does_intersect |= seq_edit_split_effect_intersect_check(seq->seq3, timeline_frame); + if ((seq->seq1->type & SEQ_TYPE_EFFECT) != 0) { + input_does_intersect |= seq_edit_split_effect_inputs_intersect(seq->seq3, timeline_frame); + } + } + return input_does_intersect; +} + +static bool seq_edit_split_operation_permitted_check(SeqCollection *strips, + const int timeline_frame, + const char **r_error) +{ + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, strips) { + if ((seq->type & SEQ_TYPE_EFFECT) == 0) { + continue; + } + if (!seq_edit_split_effect_intersect_check(seq, timeline_frame)) { + continue; + } + if (SEQ_effect_get_num_inputs(seq->type) <= 1) { + continue; + } + if (ELEM(seq->type, SEQ_TYPE_CROSS, SEQ_TYPE_GAMCROSS, SEQ_TYPE_WIPE)) { + *r_error = "Splitting transition effect is not permitted."; + return false; + } + if (!seq_edit_split_effect_inputs_intersect(seq, timeline_frame)) { + *r_error = "Effect inputs don't overlap. Can not split such effect."; + return false; + } + } + return true; } /** @@ -390,16 +457,23 @@ Sequence *SEQ_edit_strip_split(Main *bmain, ListBase *seqbase, Sequence *seq, const int timeline_frame, - const eSeqSplitMethod method) + const eSeqSplitMethod method, + const char **r_error) { - if (timeline_frame <= seq->startdisp || timeline_frame >= seq->enddisp) { + if (!seq_edit_split_effect_intersect_check(seq, timeline_frame)) { return NULL; } + /* Whole strip chain must be duplicated in order to preserve relationships. */ SeqCollection *collection = SEQ_collection_create(__func__); SEQ_collection_append_strip(seq, collection); SEQ_collection_expand(seqbase, collection, SEQ_query_strip_effect_chain); + if (!seq_edit_split_operation_permitted_check(collection, timeline_frame, r_error)) { + SEQ_collection_free(collection); + return NULL; + } + /* Move strips in collection from seqbase to new ListBase. */ ListBase left_strips = {NULL, NULL}; SEQ_ITERATOR_FOREACH (seq, collection) { @@ -421,7 +495,19 @@ Sequence *SEQ_edit_strip_split(Main *bmain, Sequence *left_seq = left_strips.first; Sequence *right_seq = right_strips.first; Sequence *return_seq = right_strips.first; + + /* Strips can't be tagged while in detached `seqbase`. Collect all strips which needs to be + * deleted and delay tagging until they are moved back to `seqbase` in `Editing`. */ + SeqCollection *strips_to_delete = SEQ_collection_create(__func__); + while (left_seq && right_seq) { + if (left_seq->startdisp >= timeline_frame) { + SEQ_collection_append_strip(left_seq, strips_to_delete); + } + if (right_seq->enddisp <= timeline_frame) { + SEQ_collection_append_strip(right_seq, strips_to_delete); + } + seq_edit_split_handle_strip_offsets(bmain, scene, left_seq, right_seq, timeline_frame, method); left_seq = left_seq->next; right_seq = right_seq->next; @@ -435,6 +521,12 @@ Sequence *SEQ_edit_strip_split(Main *bmain, SEQ_ensure_unique_name(seq, scene); } + Sequence *seq_delete; + SEQ_ITERATOR_FOREACH (seq_delete, strips_to_delete) { + SEQ_edit_flag_for_removal(scene, seqbase, seq_delete); + } + SEQ_edit_remove_flagged_sequences(scene, seqbase); + SEQ_collection_free(strips_to_delete); return return_seq; } @@ -476,6 +568,6 @@ bool SEQ_edit_remove_gaps(Scene *scene, void SEQ_edit_sequence_name_set(Scene *scene, Sequence *seq, const char *new_name) { BLI_strncpy_utf8(seq->name + 2, new_name, MAX_NAME - 2); - BLI_utf8_invalid_strip(seq->name + 2, strlen(seq->name + 2)); + BLI_str_utf8_invalid_strip(seq->name + 2, strlen(seq->name + 2)); SEQ_sequence_lookup_tag(scene, SEQ_LOOKUP_TAG_INVALID); } diff --git a/source/blender/sequencer/intern/strip_relations.c b/source/blender/sequencer/intern/strip_relations.c index 7c5a3f031db..ec70a683da5 100644 --- a/source/blender/sequencer/intern/strip_relations.c +++ b/source/blender/sequencer/intern/strip_relations.c @@ -118,7 +118,7 @@ static void sequence_invalidate_cache(Scene *scene, } if (seq->effectdata && seq->type == SEQ_TYPE_SPEED) { - seq_effect_speed_rebuild_map(scene, seq, true); + seq_effect_speed_rebuild_map(scene, seq); } sequence_do_invalidate_dependent(scene, seq, &ed->seqbase); @@ -268,7 +268,7 @@ void SEQ_relations_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render) SEQ_relations_sequence_free_anim(seq); } if (seq->type == SEQ_TYPE_SPEED) { - seq_effect_speed_rebuild_map(scene, seq, true); + seq_effect_speed_rebuild_map(scene, seq); } } if (seq->type == SEQ_TYPE_META) { @@ -325,7 +325,7 @@ static bool update_changed_seq_recurs( SEQ_relations_sequence_free_anim(seq); } else if (seq->type == SEQ_TYPE_SPEED) { - seq_effect_speed_rebuild_map(scene, seq, true); + seq_effect_speed_rebuild_map(scene, seq); } } @@ -504,3 +504,23 @@ void SEQ_relations_check_uuids_unique_and_report(const Scene *scene) BLI_gset_free(used_uuids, NULL); } + +/* Return immediate parent meta of sequence */ +struct Sequence *SEQ_find_metastrip_by_sequence(ListBase *seqbase, Sequence *meta, Sequence *seq) +{ + Sequence *iseq; + + for (iseq = seqbase->first; iseq; iseq = iseq->next) { + Sequence *rval; + + if (seq == iseq) { + return meta; + } + if (iseq->seqbase.first && + (rval = SEQ_find_metastrip_by_sequence(&iseq->seqbase, iseq, seq))) { + return rval; + } + } + + return NULL; +}
\ No newline at end of file diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c index c9af2fced65..9f69f434ca0 100644 --- a/source/blender/sequencer/intern/strip_transform.c +++ b/source/blender/sequencer/intern/strip_transform.c @@ -40,6 +40,10 @@ #include "SEQ_time.h" #include "SEQ_transform.h" +#include "CLG_log.h" + +static CLG_LogRef LOG = {"seq.strip_transform"}; + static int seq_tx_get_start(Sequence *seq) { return seq->start; @@ -315,6 +319,12 @@ static int shuffle_seq_time_offset_test(SeqCollection *strips_to_shuffle, if (!seq_overlap(seq, seq_other)) { continue; } + if (UNLIKELY(SEQ_collection_has_strip(seq_other, strips_to_shuffle))) { + CLOG_WARN(&LOG, + "Strip overlaps with itself or another strip, that is to be shuffled." + "This should never happen."); + continue; + } if (dir == 'L') { offset = min_ii(offset, seq_other->startdisp - seq->enddisp); } diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c index 98640ea8a5c..f946affe1d8 100644 --- a/source/blender/sequencer/intern/utils.c +++ b/source/blender/sequencer/intern/utils.c @@ -431,7 +431,7 @@ const Sequence *SEQ_get_topmost_sequence(const Scene *scene, int frame) return best_seq; } -/* in cases where we done know the sequence's listbase */ +/* in cases where we don't know the sequence's listbase */ ListBase *SEQ_get_seqbase_by_seq(ListBase *seqbase, Sequence *seq) { Sequence *iseq; @@ -449,25 +449,6 @@ ListBase *SEQ_get_seqbase_by_seq(ListBase *seqbase, Sequence *seq) return NULL; } -Sequence *seq_find_metastrip_by_sequence(ListBase *seqbase, Sequence *meta, Sequence *seq) -{ - Sequence *iseq; - - for (iseq = seqbase->first; iseq; iseq = iseq->next) { - Sequence *rval; - - if (seq == iseq) { - return meta; - } - if (iseq->seqbase.first && - (rval = seq_find_metastrip_by_sequence(&iseq->seqbase, iseq, seq))) { - return rval; - } - } - - return NULL; -} - /** * Only use as last resort when the StripElem is available but no the Sequence. * (needed for RNA) diff --git a/source/blender/sequencer/intern/utils.h b/source/blender/sequencer/intern/utils.h index 97f33bb3ae0..7aee7d229c9 100644 --- a/source/blender/sequencer/intern/utils.h +++ b/source/blender/sequencer/intern/utils.h @@ -31,10 +31,6 @@ struct Scene; bool sequencer_seq_generates_image(struct Sequence *seq); void seq_open_anim_file(struct Scene *scene, struct Sequence *seq, bool openfile); -struct Sequence *seq_find_metastrip_by_sequence(ListBase *seqbase /* = ed->seqbase */, - struct Sequence *meta /* = NULL */, - struct Sequence *seq); - #ifdef __cplusplus } #endif diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index b5a038757c2..f1a8f4ffd71 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -2497,7 +2497,7 @@ static int radial_control_get_path(PointerRNA *ctx_ptr, /* get an rna string path from the operator's properties */ char *str; - if (!(str = RNA_string_get_alloc(op->ptr, name, NULL, 0))) { + if (!(str = RNA_string_get_alloc(op->ptr, name, NULL, 0, NULL))) { return 1; } diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index 0f9665f0a95..79632e49c1f 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -741,10 +741,17 @@ if(WITH_COMPOSITOR) endif() set(geo_node_tests + attributes + curve_primitives curves geometry + mesh_primitives mesh points + utilities + vector + volume + ) foreach(geo_node_test ${geo_node_tests}) |