From c4a4eb4112f7ccf93c7d7a9b39a8703a8fba7405 Mon Sep 17 00:00:00 2001 From: Aras Pranckevicius Date: Wed, 3 Jan 2024 11:34:59 +0200 Subject: [PATCH 01/11] VSE: factor out sequencer_scopes.hh header --- .../editors/space_sequencer/CMakeLists.txt | 1 + .../editors/space_sequencer/sequencer_intern.hh | 8 -------- .../space_sequencer/sequencer_preview_draw.cc | 2 +- .../editors/space_sequencer/sequencer_scopes.cc | 14 +++++++++++++- .../editors/space_sequencer/sequencer_scopes.hh | 17 +++++++++++++++++ 5 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 source/blender/editors/space_sequencer/sequencer_scopes.hh diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt index f6656599d85..cb9c834869c 100644 --- a/source/blender/editors/space_sequencer/CMakeLists.txt +++ b/source/blender/editors/space_sequencer/CMakeLists.txt @@ -46,6 +46,7 @@ set(SRC sequencer_intern.hh sequencer_quads_batch.hh + sequencer_scopes.hh ) set(LIB diff --git a/source/blender/editors/space_sequencer/sequencer_intern.hh b/source/blender/editors/space_sequencer/sequencer_intern.hh index cbbb220adcd..f7308f6cc6b 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.hh +++ b/source/blender/editors/space_sequencer/sequencer_intern.hh @@ -258,14 +258,6 @@ void sequencer_dropboxes(); void sequencer_operatortypes(); void sequencer_keymap(wmKeyConfig *keyconf); -/* sequencer_scope.c */ - -ImBuf *make_waveform_view_from_ibuf(ImBuf *ibuf); -ImBuf *make_sep_waveform_view_from_ibuf(ImBuf *ibuf); -ImBuf *make_vectorscope_view_from_ibuf(ImBuf *ibuf); -ImBuf *make_zebra_view_from_ibuf(ImBuf *ibuf, float perc); -ImBuf *make_histogram_view_from_ibuf(ImBuf *ibuf); - /* `sequencer_buttons.cc` */ void sequencer_buttons_register(ARegionType *art); diff --git a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc index 8c7c685f1ef..aed7b59318d 100644 --- a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc +++ b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc @@ -56,8 +56,8 @@ #include "WM_api.hh" #include "WM_types.hh" -/* Own include. */ #include "sequencer_intern.hh" +#include "sequencer_scopes.hh" static Sequence *special_seq_update = nullptr; diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.cc b/source/blender/editors/space_sequencer/sequencer_scopes.cc index df294930974..b53061c0a1f 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.cc +++ b/source/blender/editors/space_sequencer/sequencer_scopes.cc @@ -17,7 +17,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#include "sequencer_intern.hh" +#include "sequencer_scopes.hh" // #define DEBUG_TIME @@ -506,6 +506,9 @@ static void make_histogram_view_from_ibuf_reduce(const void *__restrict /*userda static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf) { +#ifdef DEBUG_TIME + SCOPED_TIMER_AVERAGED(__func__); +#endif ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect); int x; uint nr, ng, nb; @@ -590,6 +593,9 @@ static void make_histogram_view_from_ibuf_float_fn(void *__restrict userdata, static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf) { +#ifdef DEBUG_TIME + SCOPED_TIMER_AVERAGED(__func__); +#endif ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect); int nr, ng, nb; int x; @@ -679,6 +685,9 @@ static void vectorscope_put_cross(uchar r, uchar g, uchar b, uchar *tgt, int w, static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf) { +#ifdef DEBUG_TIME + SCOPED_TIMER_AVERAGED(__func__); +#endif ImBuf *rval = IMB_allocImBuf(515, 515, 32, IB_rect); int x, y; const uchar *src = ibuf->byte_buffer.data; @@ -724,6 +733,9 @@ static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf) static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf) { +#ifdef DEBUG_TIME + SCOPED_TIMER_AVERAGED(__func__); +#endif ImBuf *rval = IMB_allocImBuf(515, 515, 32, IB_rect); int x, y; const float *src = ibuf->float_buffer.data; diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.hh b/source/blender/editors/space_sequencer/sequencer_scopes.hh new file mode 100644 index 00000000000..bbc2a115cac --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_scopes.hh @@ -0,0 +1,17 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup spseq + */ + +#pragma once + +struct ImBuf; + +ImBuf *make_waveform_view_from_ibuf(ImBuf *ibuf); +ImBuf *make_sep_waveform_view_from_ibuf(ImBuf *ibuf); +ImBuf *make_vectorscope_view_from_ibuf(ImBuf *ibuf); +ImBuf *make_zebra_view_from_ibuf(ImBuf *ibuf, float perc); +ImBuf *make_histogram_view_from_ibuf(ImBuf *ibuf); -- 2.30.2 From 048a280085d254fc34598db716b4241956bba579 Mon Sep 17 00:00:00 2001 From: Aras Pranckevicius Date: Wed, 3 Jan 2024 12:08:54 +0200 Subject: [PATCH 02/11] VSE: refactor, move Scopes into runtime data, and make SpaceSeq runtime data a pointer --- .../blenloader/intern/versioning_260.cc | 1 + .../blenloader/intern/versioning_280.cc | 1 + .../blenloader/intern/versioning_290.cc | 1 + .../blenloader/intern/versioning_300.cc | 1 + .../sequencer_channels_draw.cc | 4 +- .../sequencer_channels_edit.cc | 2 +- .../space_sequencer/sequencer_intern.hh | 19 ++++++ .../space_sequencer/sequencer_preview_draw.cc | 2 +- .../space_sequencer/sequencer_scopes.cc | 19 ++++++ .../space_sequencer/sequencer_scopes.hh | 14 ++++ .../space_sequencer/sequencer_thumbnails.cc | 18 ++--- .../space_sequencer/space_sequencer.cc | 67 ++++++------------- .../transform/transform_convert_sequencer.cc | 1 + .../transform_convert_sequencer_image.cc | 1 + .../transform_convert_sequencer_retiming.cc | 1 + .../editors/transform/transform_gizmo_2d.cc | 1 + .../transform/transform_snap_sequencer.cc | 2 + .../blender/imbuf/intern/colormanagement.cc | 1 + source/blender/makesdna/DNA_sequence_types.h | 18 +---- source/blender/makesdna/DNA_space_types.h | 17 ++--- source/blender/makesrna/intern/rna_userdef.cc | 1 + source/blender/sequencer/SEQ_sound.hh | 1 + .../blender/windowmanager/intern/wm_files.cc | 1 + 23 files changed, 105 insertions(+), 89 deletions(-) diff --git a/source/blender/blenloader/intern/versioning_260.cc b/source/blender/blenloader/intern/versioning_260.cc index 6b972535177..c412820cf52 100644 --- a/source/blender/blenloader/intern/versioning_260.cc +++ b/source/blender/blenloader/intern/versioning_260.cc @@ -34,6 +34,7 @@ #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_sdna_types.h" +#include "DNA_sequence_types.h" #include "DNA_space_types.h" #include "DNA_text_types.h" #include "DNA_view3d_types.h" diff --git a/source/blender/blenloader/intern/versioning_280.cc b/source/blender/blenloader/intern/versioning_280.cc index ef7fb3747e4..dab93df9593 100644 --- a/source/blender/blenloader/intern/versioning_280.cc +++ b/source/blender/blenloader/intern/versioning_280.cc @@ -50,6 +50,7 @@ #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "DNA_sequence_types.h" #include "DNA_shader_fx_types.h" #include "DNA_text_types.h" #include "DNA_texture_types.h" diff --git a/source/blender/blenloader/intern/versioning_290.cc b/source/blender/blenloader/intern/versioning_290.cc index db9ff3f75bf..70559b8991c 100644 --- a/source/blender/blenloader/intern/versioning_290.cc +++ b/source/blender/blenloader/intern/versioning_290.cc @@ -37,6 +37,7 @@ #include "DNA_pointcloud_types.h" #include "DNA_rigidbody_types.h" #include "DNA_screen_types.h" +#include "DNA_sequence_types.h" #include "DNA_shader_fx_types.h" #include "DNA_space_types.h" #include "DNA_text_types.h" diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc index de27a5292d8..b31cc4d086f 100644 --- a/source/blender/blenloader/intern/versioning_300.cc +++ b/source/blender/blenloader/intern/versioning_300.cc @@ -46,6 +46,7 @@ #include "DNA_modifier_types.h" #include "DNA_movieclip_types.h" #include "DNA_screen_types.h" +#include "DNA_sequence_types.h" #include "DNA_space_types.h" #include "DNA_text_types.h" #include "DNA_tracking_types.h" diff --git a/source/blender/editors/space_sequencer/sequencer_channels_draw.cc b/source/blender/editors/space_sequencer/sequencer_channels_draw.cc index b43bce18097..279baf479a2 100644 --- a/source/blender/editors/space_sequencer/sequencer_channels_draw.cc +++ b/source/blender/editors/space_sequencer/sequencer_channels_draw.cc @@ -179,7 +179,7 @@ static float draw_channel_widget_lock(const SeqChannelDrawContext *context, static bool channel_is_being_renamed(const SpaceSeq *sseq, const int channel_index) { - return sseq->runtime.rename_channel_index == channel_index; + return sseq->runtime->rename_channel_index == channel_index; } static float text_size_get(const SeqChannelDrawContext *context) @@ -250,7 +250,7 @@ static void draw_channel_labels(const SeqChannelDrawContext *context, UI_block_emboss_set(block, UI_EMBOSS_NONE); if (UI_but_active_only(context->C, context->region, block, but) == false) { - sseq->runtime.rename_channel_index = 0; + sseq->runtime->rename_channel_index = 0; } WM_event_add_notifier(context->C, NC_SCENE | ND_SEQUENCER, context->scene); diff --git a/source/blender/editors/space_sequencer/sequencer_channels_edit.cc b/source/blender/editors/space_sequencer/sequencer_channels_edit.cc index df24b3f5a9c..549711cfbc3 100644 --- a/source/blender/editors/space_sequencer/sequencer_channels_edit.cc +++ b/source/blender/editors/space_sequencer/sequencer_channels_edit.cc @@ -38,7 +38,7 @@ static int sequencer_rename_channel_invoke(bContext *C, wmOperator * /*op*/, con channel_draw_context_init(C, CTX_wm_region(C), &context); float mouse_y = UI_view2d_region_to_view_y(context.timeline_region_v2d, event->mval[1]); - sseq->runtime.rename_channel_index = mouse_y; + sseq->runtime->rename_channel_index = mouse_y; WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, CTX_data_scene(C)); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_sequencer/sequencer_intern.hh b/source/blender/editors/space_sequencer/sequencer_intern.hh index f7308f6cc6b..8005dacbd72 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.hh +++ b/source/blender/editors/space_sequencer/sequencer_intern.hh @@ -13,6 +13,8 @@ #include "DNA_sequence_types.h" #include "RNA_access.hh" +#include "sequencer_scopes.hh" + /* Internal exports only. */ class SeqQuadsBatch; @@ -40,6 +42,23 @@ struct ListBase; #define DEFAULT_IMG_STRIP_LENGTH 25 /* XXX arbitrary but ok for now. */ #define OVERLAP_ALPHA 180 +struct SpaceSeq_Runtime { + /** Required for Thumbnail job start condition. */ + rctf last_thumbnail_area = {0, 0, 0, 0}; + /** Stores lists of most recently displayed thumbnails. */ + GHash *last_displayed_thumbnails = nullptr; + int rename_channel_index = 0; + float timeline_clamp_custom_range = 0; + + SequencerScopes scopes; + + SpaceSeq_Runtime() = default; + SpaceSeq_Runtime(const SpaceSeq_Runtime &) = delete; + void operator=(const SpaceSeq_Runtime &) = delete; + + ~SpaceSeq_Runtime(); +}; + struct SeqChannelDrawContext { const bContext *C; ScrArea *area; diff --git a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc index aed7b59318d..71b003229e9 100644 --- a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc +++ b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc @@ -561,7 +561,7 @@ static void sequencer_draw_display_buffer(const bContext *C, static ImBuf *sequencer_get_scope(Scene *scene, SpaceSeq *sseq, ImBuf *ibuf, bool draw_backdrop) { ImBuf *scope = nullptr; - SequencerScopes *scopes = &sseq->scopes; + SequencerScopes *scopes = &sseq->runtime->scopes; if (!draw_backdrop && (sseq->mainb != SEQ_DRAW_IMG_IMBUF || sseq->zebra != 0)) { sequencer_check_scopes(scopes, ibuf); diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.cc b/source/blender/editors/space_sequencer/sequencer_scopes.cc index b53061c0a1f..a35d9d6021e 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.cc +++ b/source/blender/editors/space_sequencer/sequencer_scopes.cc @@ -25,6 +25,25 @@ # include "BLI_timeit.hh" #endif +SequencerScopes::~SequencerScopes() +{ + if (zebra_ibuf) { + IMB_freeImBuf(zebra_ibuf); + } + if (waveform_ibuf) { + IMB_freeImBuf(waveform_ibuf); + } + if (sep_waveform_ibuf) { + IMB_freeImBuf(sep_waveform_ibuf); + } + if (vector_ibuf) { + IMB_freeImBuf(vector_ibuf); + } + if (histogram_ibuf) { + IMB_freeImBuf(histogram_ibuf); + } +} + /* XXX(@ideasman42): why is this function better than BLI_math version? * only difference is it does some normalize after, need to double check on this. */ static void rgb_to_yuv_normalized(const float rgb[3], float yuv[3]) diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.hh b/source/blender/editors/space_sequencer/sequencer_scopes.hh index bbc2a115cac..ab6721a490c 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.hh +++ b/source/blender/editors/space_sequencer/sequencer_scopes.hh @@ -10,6 +10,20 @@ struct ImBuf; +struct SequencerScopes { + SequencerScopes() = default; + ~SequencerScopes(); + SequencerScopes(const SequencerScopes &) = delete; + void operator=(const SequencerScopes &) = delete; + + ImBuf *reference_ibuf = nullptr; + ImBuf *zebra_ibuf = nullptr; + ImBuf *waveform_ibuf = nullptr; + ImBuf *sep_waveform_ibuf = nullptr; + ImBuf *vector_ibuf = nullptr; + ImBuf *histogram_ibuf = nullptr; +}; + ImBuf *make_waveform_view_from_ibuf(ImBuf *ibuf); ImBuf *make_sep_waveform_view_from_ibuf(ImBuf *ibuf); ImBuf *make_vectorscope_view_from_ibuf(ImBuf *ibuf); diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.cc b/source/blender/editors/space_sequencer/sequencer_thumbnails.cc index 902f25c1f87..7f56052cfbb 100644 --- a/source/blender/editors/space_sequencer/sequencer_thumbnails.cc +++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.cc @@ -295,21 +295,21 @@ static void sequencer_thumbnail_start_job_if_necessary( /* Job start requested, but over area which has been processed. Unless `thumbnail_is_missing` is * true, ignore this request as all images are in view. */ - if (v2d->cur.xmax == sseq->runtime.last_thumbnail_area.xmax && - v2d->cur.ymax == sseq->runtime.last_thumbnail_area.ymax && !thumbnail_is_missing) + if (v2d->cur.xmax == sseq->runtime->last_thumbnail_area.xmax && + v2d->cur.ymax == sseq->runtime->last_thumbnail_area.ymax && !thumbnail_is_missing) { return; } /* Stop the job first as view has changed. Pointless to continue old job. */ - if (v2d->cur.xmax != sseq->runtime.last_thumbnail_area.xmax || - v2d->cur.ymax != sseq->runtime.last_thumbnail_area.ymax) + if (v2d->cur.xmax != sseq->runtime->last_thumbnail_area.xmax || + v2d->cur.ymax != sseq->runtime->last_thumbnail_area.ymax) { WM_jobs_stop(CTX_wm_manager(C), nullptr, thumbnail_start_job); } sequencer_thumbnail_init_job(C, v2d, ed, thumb_height); - sseq->runtime.last_thumbnail_area = v2d->cur; + sseq->runtime->last_thumbnail_area = v2d->cur; } void last_displayed_thumbnails_list_free(void *val) @@ -320,15 +320,15 @@ void last_displayed_thumbnails_list_free(void *val) static GSet *last_displayed_thumbnails_list_ensure(const bContext *C, Sequence *seq) { SpaceSeq *sseq = CTX_wm_space_seq(C); - if (sseq->runtime.last_displayed_thumbnails == nullptr) { - sseq->runtime.last_displayed_thumbnails = BLI_ghash_ptr_new(__func__); + if (sseq->runtime->last_displayed_thumbnails == nullptr) { + sseq->runtime->last_displayed_thumbnails = BLI_ghash_ptr_new(__func__); } GSet *displayed_thumbnails = static_cast( - BLI_ghash_lookup(sseq->runtime.last_displayed_thumbnails, seq)); + BLI_ghash_lookup(sseq->runtime->last_displayed_thumbnails, seq)); if (displayed_thumbnails == nullptr) { displayed_thumbnails = BLI_gset_int_new(__func__); - BLI_ghash_insert(sseq->runtime.last_displayed_thumbnails, seq, displayed_thumbnails); + BLI_ghash_insert(sseq->runtime->last_displayed_thumbnails, seq, displayed_thumbnails); } return displayed_thumbnails; diff --git a/source/blender/editors/space_sequencer/space_sequencer.cc b/source/blender/editors/space_sequencer/space_sequencer.cc index cccd6df2753..7ae3b8619e9 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.cc +++ b/source/blender/editors/space_sequencer/space_sequencer.cc @@ -62,8 +62,15 @@ static void sequencer_scopes_tag_refresh(ScrArea *area) { SpaceSeq *sseq = (SpaceSeq *)area->spacedata.first; + sseq->runtime->scopes.reference_ibuf = nullptr; +} - sseq->scopes.reference_ibuf = nullptr; +SpaceSeq_Runtime::~SpaceSeq_Runtime() +{ + if (last_displayed_thumbnails != nullptr) { + BLI_ghash_free(last_displayed_thumbnails, nullptr, last_displayed_thumbnails_list_free); + last_displayed_thumbnails = nullptr; + } } /* ******************** manage regions ********************* */ @@ -98,9 +105,6 @@ static SpaceLink *sequencer_create(const ScrArea * /*area*/, const Scene *scene) SEQ_TIMELINE_SHOW_FCURVES | SEQ_TIMELINE_SHOW_STRIP_COLOR_TAG | SEQ_TIMELINE_SHOW_STRIP_RETIMING | SEQ_TIMELINE_ALL_WAVEFORMS; - BLI_rctf_init(&sseq->runtime.last_thumbnail_area, 0.0f, 0.0f, 0.0f, 0.0f); - sseq->runtime.last_displayed_thumbnails = nullptr; - /* Header. */ region = MEM_cnew("header for sequencer"); @@ -192,8 +196,6 @@ static SpaceLink *sequencer_create(const ScrArea * /*area*/, const Scene *scene) region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL; region->v2d.align = V2D_ALIGN_NO_NEG_Y; - sseq->runtime.last_displayed_thumbnails = nullptr; - return (SpaceLink *)sseq; } @@ -201,43 +203,23 @@ static SpaceLink *sequencer_create(const ScrArea * /*area*/, const Scene *scene) static void sequencer_free(SpaceLink *sl) { SpaceSeq *sseq = (SpaceSeq *)sl; - SequencerScopes *scopes = &sseq->scopes; + MEM_delete(sseq->runtime); #if 0 if (sseq->gpd) { BKE_gpencil_free_data(sseq->gpd); } #endif - - if (scopes->zebra_ibuf) { - IMB_freeImBuf(scopes->zebra_ibuf); - } - - if (scopes->waveform_ibuf) { - IMB_freeImBuf(scopes->waveform_ibuf); - } - - if (scopes->sep_waveform_ibuf) { - IMB_freeImBuf(scopes->sep_waveform_ibuf); - } - - if (scopes->vector_ibuf) { - IMB_freeImBuf(scopes->vector_ibuf); - } - - if (scopes->histogram_ibuf) { - IMB_freeImBuf(scopes->histogram_ibuf); - } - - if (sseq->runtime.last_displayed_thumbnails) { - BLI_ghash_free( - sseq->runtime.last_displayed_thumbnails, nullptr, last_displayed_thumbnails_list_free); - sseq->runtime.last_displayed_thumbnails = nullptr; - } } /* Space-type init callback. */ -static void sequencer_init(wmWindowManager * /*wm*/, ScrArea * /*area*/) {} +static void sequencer_init(wmWindowManager * /*wm*/, ScrArea *area) +{ + SpaceSeq *sseq = (SpaceSeq *)area->spacedata.first; + if (sseq->runtime == nullptr) { + sseq->runtime = MEM_new(__func__); + } +} static void sequencer_refresh(const bContext *C, ScrArea *area) { @@ -301,13 +283,11 @@ static void sequencer_refresh(const bContext *C, ScrArea *area) static SpaceLink *sequencer_duplicate(SpaceLink *sl) { SpaceSeq *sseqn = static_cast(MEM_dupallocN(sl)); + sseqn->runtime = MEM_new(__func__); /* Clear or remove stuff from old. */ // sseq->gpd = gpencil_data_duplicate(sseq->gpd, false); - memset(&sseqn->scopes, 0, sizeof(sseqn->scopes)); - memset(&sseqn->runtime, 0, sizeof(sseqn->runtime)); - return (SpaceLink *)sseqn; } @@ -534,7 +514,7 @@ static void sequencer_main_clamp_view(const bContext *C, ARegion *region) } /* If strip is deleted, don't move view automatically, keep current range until it is changed. */ - strip_boundbox.ymax = max_ff(sseq->runtime.timeline_clamp_custom_range, strip_boundbox.ymax); + strip_boundbox.ymax = max_ff(sseq->runtime->timeline_clamp_custom_range, strip_boundbox.ymax); rctf view_clamped = v2d->cur; @@ -557,7 +537,7 @@ static void sequencer_main_region_clamp_custom_set(const bContext *C, ARegion *r View2D *v2d = ®ion->v2d; if ((v2d->flag & V2D_IS_NAVIGATING) == 0) { - sseq->runtime.timeline_clamp_custom_range = v2d->cur.ymax; + sseq->runtime->timeline_clamp_custom_range = v2d->cur.ymax; } } @@ -960,6 +940,8 @@ static void sequencer_space_blend_read_data(BlendDataReader * /*reader*/, SpaceL { SpaceSeq *sseq = (SpaceSeq *)sl; + sseq->runtime = nullptr; + /* grease pencil data is not a direct data and can't be linked from direct_link* * functions, it should be linked from lib_link* functions instead * @@ -973,13 +955,6 @@ static void sequencer_space_blend_read_data(BlendDataReader * /*reader*/, SpaceL BKE_gpencil_blend_read_data(fd, sseq->gpd); } #endif - sseq->scopes.reference_ibuf = nullptr; - sseq->scopes.zebra_ibuf = nullptr; - sseq->scopes.waveform_ibuf = nullptr; - sseq->scopes.sep_waveform_ibuf = nullptr; - sseq->scopes.vector_ibuf = nullptr; - sseq->scopes.histogram_ibuf = nullptr; - memset(&sseq->runtime, 0x0, sizeof(sseq->runtime)); } static void sequencer_space_blend_write(BlendWriter *writer, SpaceLink *sl) diff --git a/source/blender/editors/transform/transform_convert_sequencer.cc b/source/blender/editors/transform/transform_convert_sequencer.cc index 68b115ae28d..6113600eb1e 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.cc +++ b/source/blender/editors/transform/transform_convert_sequencer.cc @@ -6,6 +6,7 @@ * \ingroup edtransform */ +#include "DNA_sequence_types.h" #include "DNA_space_types.h" #include "MEM_guardedalloc.h" diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.cc b/source/blender/editors/transform/transform_convert_sequencer_image.cc index 2f5594d8750..05d38c5bcd7 100644 --- a/source/blender/editors/transform/transform_convert_sequencer_image.cc +++ b/source/blender/editors/transform/transform_convert_sequencer_image.cc @@ -8,6 +8,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_sequence_types.h" #include "DNA_space_types.h" #include "BLI_listbase.h" diff --git a/source/blender/editors/transform/transform_convert_sequencer_retiming.cc b/source/blender/editors/transform/transform_convert_sequencer_retiming.cc index 93eb527b2bf..5b4990fc8ba 100644 --- a/source/blender/editors/transform/transform_convert_sequencer_retiming.cc +++ b/source/blender/editors/transform/transform_convert_sequencer_retiming.cc @@ -8,6 +8,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_sequence_types.h" #include "DNA_space_types.h" #include "BLI_listbase.h" diff --git a/source/blender/editors/transform/transform_gizmo_2d.cc b/source/blender/editors/transform/transform_gizmo_2d.cc index db4f88a3a2e..f410151dbb8 100644 --- a/source/blender/editors/transform/transform_gizmo_2d.cc +++ b/source/blender/editors/transform/transform_gizmo_2d.cc @@ -19,6 +19,7 @@ #include "DNA_object_types.h" #include "DNA_screen_types.h" +#include "DNA_sequence_types.h" #include "DNA_space_types.h" #include "DNA_view3d_types.h" diff --git a/source/blender/editors/transform/transform_snap_sequencer.cc b/source/blender/editors/transform/transform_snap_sequencer.cc index e46b602951f..e17caa7f2fe 100644 --- a/source/blender/editors/transform/transform_snap_sequencer.cc +++ b/source/blender/editors/transform/transform_snap_sequencer.cc @@ -14,6 +14,8 @@ #include "BKE_context.hh" +#include "DNA_sequence_types.h" + #include "ED_screen.hh" #include "ED_transform.hh" diff --git a/source/blender/imbuf/intern/colormanagement.cc b/source/blender/imbuf/intern/colormanagement.cc index 11a09ed944d..88e4ce3202f 100644 --- a/source/blender/imbuf/intern/colormanagement.cc +++ b/source/blender/imbuf/intern/colormanagement.cc @@ -16,6 +16,7 @@ #include "DNA_image_types.h" #include "DNA_movieclip_types.h" #include "DNA_scene_types.h" +#include "DNA_sequence_types.h" #include "DNA_space_types.h" #include "IMB_filetype.h" diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index d78c2fa7bdf..0806401c84b 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -545,19 +545,9 @@ typedef struct SoundEqualizerModifierData { /** \} */ /* -------------------------------------------------------------------- */ -/** \name Scopes +/** \name Flags & Types * \{ */ -typedef struct SequencerScopes { - struct ImBuf *reference_ibuf; - - struct ImBuf *zebra_ibuf; - struct ImBuf *waveform_ibuf; - struct ImBuf *sep_waveform_ibuf; - struct ImBuf *vector_ibuf; - struct ImBuf *histogram_ibuf; -} SequencerScopes; - #define MAXSEQ 128 /** #Editor::overlay_frame_flag */ @@ -583,12 +573,6 @@ enum { SEQ_SPEED_USE_INTERPOLATION = 1 << 3, }; -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Flags & Types - * \{ */ - #define SEQ_NAME_MAXSTR 64 /* From: `DNA_object_types.h`, see it's doc-string there. */ diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 6fc3eea2580..3de669f62e5 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -19,7 +19,6 @@ #include "DNA_movieclip_types.h" /* MovieClipUser */ #include "DNA_node_types.h" /* for bNodeInstanceKey */ #include "DNA_outliner_types.h" /* for TreeStoreElem */ -#include "DNA_sequence_types.h" /* SequencerScopes */ #include "DNA_vec_types.h" /* Hum ... Not really nice... but needed for spacebuts. */ #include "DNA_view2d_types.h" @@ -75,6 +74,9 @@ typedef struct SpaceOutliner_Runtime SpaceOutliner_Runtime; /** Defined in `file_intern.hh`. */ typedef struct SpaceFile_Runtime SpaceFile_Runtime; +/** Defined in `sequencer_intern.hh`. */ +typedef struct SpaceSeq_Runtime SpaceSeq_Runtime; + /** Defined in `spreadsheet_intern.hh`. */ typedef struct SpaceSpreadsheet_Runtime SpaceSpreadsheet_Runtime; @@ -631,15 +633,6 @@ typedef enum eSpaceSeq_SequencerTimelineOverlay_Flag { SEQ_TIMELINE_SHOW_GRID = (1 << 18), } eSpaceSeq_SequencerTimelineOverlay_Flag; -typedef struct SpaceSeqRuntime { - /** Required for Thumbnail job start condition. */ - struct rctf last_thumbnail_area; - /** Stores lists of most recently displayed thumbnails. */ - struct GHash *last_displayed_thumbnails; - int rename_channel_index; - float timeline_clamp_custom_range; -} SpaceSeqRuntime; - /** Sequencer. */ typedef struct SpaceSeq { SpaceLink *next, *prev; @@ -678,8 +671,6 @@ typedef struct SpaceSeq { /** Grease-pencil data. */ struct bGPdata *gpd; - /** Different scoped displayed in space. */ - struct SequencerScopes scopes; struct SequencerPreviewOverlay preview_overlay; struct SequencerTimelineOverlay timeline_overlay; @@ -687,7 +678,7 @@ typedef struct SpaceSeq { char multiview_eye; char _pad2[7]; - SpaceSeqRuntime runtime; + SpaceSeq_Runtime *runtime; } SpaceSeq; /** #SpaceSeq.mainb */ diff --git a/source/blender/makesrna/intern/rna_userdef.cc b/source/blender/makesrna/intern/rna_userdef.cc index 21274e5be61..1efb3eadc61 100644 --- a/source/blender/makesrna/intern/rna_userdef.cc +++ b/source/blender/makesrna/intern/rna_userdef.cc @@ -12,6 +12,7 @@ #include "DNA_brush_types.h" #include "DNA_curve_types.h" #include "DNA_scene_types.h" +#include "DNA_sequence_types.h" #include "DNA_space_types.h" #include "DNA_userdef_types.h" #include "DNA_view3d_types.h" diff --git a/source/blender/sequencer/SEQ_sound.hh b/source/blender/sequencer/SEQ_sound.hh index a5efbb79c7c..ca77e2973b7 100644 --- a/source/blender/sequencer/SEQ_sound.hh +++ b/source/blender/sequencer/SEQ_sound.hh @@ -13,6 +13,7 @@ struct Main; struct Scene; struct Sequence; struct bSound; +struct SequenceModifierData; struct SequencerSoundEqualizer; struct SoundModifierWorkerInfo; struct BlendWriter; diff --git a/source/blender/windowmanager/intern/wm_files.cc b/source/blender/windowmanager/intern/wm_files.cc index 124bea5fc6e..8c35d08b1b2 100644 --- a/source/blender/windowmanager/intern/wm_files.cc +++ b/source/blender/windowmanager/intern/wm_files.cc @@ -54,6 +54,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "DNA_sequence_types.h" #include "DNA_space_types.h" #include "DNA_userdef_types.h" #include "DNA_windowmanager_types.h" -- 2.30.2 From 981f5e926f7a4e5613e6a2483d375457308fe9bc Mon Sep 17 00:00:00 2001 From: Aras Pranckevicius Date: Wed, 3 Jan 2024 17:22:02 +0200 Subject: [PATCH 03/11] VSE: draw histogram scope as geometry instead of low-res image --- .../space_sequencer/sequencer_intern.hh | 2 +- .../space_sequencer/sequencer_preview_draw.cc | 327 ++++++++++++------ .../space_sequencer/sequencer_scopes.cc | 263 ++++---------- .../space_sequencer/sequencer_scopes.hh | 30 +- 4 files changed, 306 insertions(+), 316 deletions(-) diff --git a/source/blender/editors/space_sequencer/sequencer_intern.hh b/source/blender/editors/space_sequencer/sequencer_intern.hh index 8005dacbd72..d4384dde56a 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.hh +++ b/source/blender/editors/space_sequencer/sequencer_intern.hh @@ -50,7 +50,7 @@ struct SpaceSeq_Runtime { int rename_channel_index = 0; float timeline_clamp_custom_range = 0; - SequencerScopes scopes; + blender::ed::seq::SeqScopes scopes; SpaceSeq_Runtime() = default; SpaceSeq_Runtime(const SpaceSeq_Runtime &) = delete; diff --git a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc index 71b003229e9..f92bbdfe605 100644 --- a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc +++ b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc @@ -57,6 +57,7 @@ #include "WM_types.hh" #include "sequencer_intern.hh" +#include "sequencer_quads_batch.hh" #include "sequencer_scopes.hh" static Sequence *special_seq_update = nullptr; @@ -158,36 +159,6 @@ ImBuf *sequencer_ibuf_get(Main *bmain, return ibuf; } -static void sequencer_check_scopes(SequencerScopes *scopes, ImBuf *ibuf) -{ - if (scopes->reference_ibuf != ibuf) { - if (scopes->zebra_ibuf) { - IMB_freeImBuf(scopes->zebra_ibuf); - scopes->zebra_ibuf = nullptr; - } - - if (scopes->waveform_ibuf) { - IMB_freeImBuf(scopes->waveform_ibuf); - scopes->waveform_ibuf = nullptr; - } - - if (scopes->sep_waveform_ibuf) { - IMB_freeImBuf(scopes->sep_waveform_ibuf); - scopes->sep_waveform_ibuf = nullptr; - } - - if (scopes->vector_ibuf) { - IMB_freeImBuf(scopes->vector_ibuf); - scopes->vector_ibuf = nullptr; - } - - if (scopes->histogram_ibuf) { - IMB_freeImBuf(scopes->histogram_ibuf); - scopes->histogram_ibuf = nullptr; - } - } -} - static ImBuf *sequencer_make_scope(Scene *scene, ImBuf *ibuf, ImBuf *(*make_scope_fn)(ImBuf *ibuf)) { ImBuf *display_ibuf = IMB_dupImBuf(ibuf); @@ -451,11 +422,9 @@ static void sequencer_draw_display_buffer(const bContext *C, ARegion *region, SpaceSeq *sseq, ImBuf *ibuf, - ImBuf *scope, bool draw_overlay, bool draw_backdrop) { - void *display_buffer; void *buffer_cache_handle = nullptr; if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) { @@ -472,21 +441,8 @@ static void sequencer_draw_display_buffer(const bContext *C, uint texCoord = GPU_vertformat_attr_add( imm_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - if (scope) { - ibuf = scope; - - if (ibuf->float_buffer.data && ibuf->byte_buffer.data == nullptr) { - IMB_rect_from_float(ibuf); - } - - display_buffer = ibuf->byte_buffer.data; - format = GPU_RGBA8; - data = GPU_DATA_UBYTE; - } - else { - display_buffer = sequencer_OCIO_transform_ibuf( - C, ibuf, &glsl_used, &format, &data, &buffer_cache_handle); - } + void *display_buffer = sequencer_OCIO_transform_ibuf( + C, ibuf, &glsl_used, &format, &data, &buffer_cache_handle); if (draw_backdrop) { GPU_matrix_push(); @@ -558,68 +514,219 @@ static void sequencer_draw_display_buffer(const bContext *C, } } -static ImBuf *sequencer_get_scope(Scene *scene, SpaceSeq *sseq, ImBuf *ibuf, bool draw_backdrop) +static void draw_histogram(const blender::ed::seq::ScopeHistogram &hist, + SeqQuadsBatch &quads, + const rctf &area) { - ImBuf *scope = nullptr; - SequencerScopes *scopes = &sseq->runtime->scopes; + if (hist.data.is_empty()) { + return; + } - if (!draw_backdrop && (sseq->mainb != SEQ_DRAW_IMG_IMBUF || sseq->zebra != 0)) { - sequencer_check_scopes(scopes, ibuf); + uchar col_grid[4] = {128, 128, 128, 128}; - switch (sseq->mainb) { - case SEQ_DRAW_IMG_IMBUF: - if (!scopes->zebra_ibuf) { + /* Grid lines. */ + float grid_x_0 = area.xmin; + float grid_x_1 = area.xmax; + if (hist.data.size() > 256) { + grid_x_0 = area.xmin + (area.xmax - area.xmin) * (0.25f / 1.5f); + grid_x_1 = area.xmin + (area.xmax - area.xmin) * (1.25f / 1.5f); + } + for (int line = 0; line <= 4; line++) { + float x = grid_x_0 + (grid_x_1 - grid_x_0) * line / 4; + quads.add_line(x, area.ymin, x, area.ymax, col_grid); + } - if (ibuf->float_buffer.data) { - ImBuf *display_ibuf = IMB_dupImBuf(ibuf); - IMB_colormanagement_imbuf_make_display_space( - display_ibuf, &scene->view_settings, &scene->display_settings); - scopes->zebra_ibuf = make_zebra_view_from_ibuf(display_ibuf, sseq->zebra); - IMB_freeImBuf(display_ibuf); - } - else { - scopes->zebra_ibuf = make_zebra_view_from_ibuf(ibuf, sseq->zebra); - } - } - scope = scopes->zebra_ibuf; - break; - case SEQ_DRAW_IMG_WAVEFORM: - if ((sseq->flag & SEQ_DRAW_COLOR_SEPARATED) != 0) { - if (!scopes->sep_waveform_ibuf) { - scopes->sep_waveform_ibuf = sequencer_make_scope( - scene, ibuf, make_sep_waveform_view_from_ibuf); - } - scope = scopes->sep_waveform_ibuf; - } - else { - if (!scopes->waveform_ibuf) { - scopes->waveform_ibuf = sequencer_make_scope( - scene, ibuf, make_waveform_view_from_ibuf); - } - scope = scopes->waveform_ibuf; - } - break; - case SEQ_DRAW_IMG_VECTORSCOPE: - if (!scopes->vector_ibuf) { - scopes->vector_ibuf = sequencer_make_scope(scene, ibuf, make_vectorscope_view_from_ibuf); - } - scope = scopes->vector_ibuf; - break; - case SEQ_DRAW_IMG_HISTOGRAM: - if (!scopes->histogram_ibuf) { - scopes->histogram_ibuf = sequencer_make_scope( - scene, ibuf, make_histogram_view_from_ibuf); - } - scope = scopes->histogram_ibuf; - break; + /* Histogram area & line for each R/G/B channels, additively blended. */ + quads.draw(); + GPU_blend(GPU_BLEND_ADDITIVE); + for (int ch = 0; ch < 3; ++ch) { + if (hist.max_value[ch] == 0) { + continue; } + uchar col_line[4] = {32, 32, 32, 255}; + uchar col_area[4] = {64, 64, 64, 128}; + col_line[ch] = 224; + col_area[ch] = 224; + float y_scale = (area.ymax - area.ymin) / hist.max_value[ch] * 0.95f; + float x_scale = (area.xmax - area.xmin) / hist.data.size(); + float yb = area.ymin; + for (int bin = 0; bin < hist.data.size() - 1; bin++) { + float x0 = area.xmin + (bin + 0.5f) * x_scale; + float x1 = area.xmin + (bin + 1.5f) * x_scale; - /* Future files may have new scopes we don't catch above. */ - if (scope) { - scopes->reference_ibuf = ibuf; + float y0 = area.ymin + hist.data[bin][ch] * y_scale; + float y1 = area.ymin + hist.data[bin + 1][ch] * y_scale; + quads.add_quad(x0, yb, x0, y0, x1, yb, x1, y1, col_area); + quads.add_line(x0, y0, x1, y1, col_line); } } - return scope; + quads.draw(); + GPU_blend(GPU_BLEND_ALPHA); +} + +static void sequencer_draw_scopes(Scene *scene, ARegion *region, SpaceSeq *sseq, bool draw_overlay) +{ + using namespace blender::ed::seq; + + /* Figure out draw coordinates. */ + rctf preview; + rctf canvas; + sequencer_preview_get_rect(&preview, scene, region, sseq, draw_overlay, false); + + if (draw_overlay && (sseq->overlay_frame_type == SEQ_OVERLAY_FRAME_TYPE_RECT)) { + canvas = scene->ed->overlay_frame_rect; + } + else { + BLI_rctf_init(&canvas, 0.0f, 1.0f, 0.0f, 1.0f); + } + + SeqQuadsBatch quads; + SeqScopes *scopes = &sseq->runtime->scopes; + + /* Draw scope image if there is one. */ + bool use_blend = sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA; + ImBuf *scope_image = nullptr; + if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) { + scope_image = scopes->zebra_ibuf; + } + else if (sseq->mainb == SEQ_DRAW_IMG_WAVEFORM) { + scope_image = (sseq->flag & SEQ_DRAW_COLOR_SEPARATED) != 0 ? scopes->sep_waveform_ibuf : + scopes->waveform_ibuf; + } + else if (sseq->mainb == SEQ_DRAW_IMG_VECTORSCOPE) { + scope_image = scopes->vector_ibuf; + } + else if (sseq->mainb == SEQ_DRAW_IMG_HISTOGRAM) { + use_blend = true; + } + + if (use_blend) { + GPU_blend(GPU_BLEND_ALPHA); + } + + if (scope_image != nullptr) { + if (scope_image->float_buffer.data && scope_image->byte_buffer.data == nullptr) { + IMB_rect_from_float(scope_image); + } + + eGPUTextureFormat format = GPU_RGBA8; + eGPUDataFormat data = GPU_DATA_UBYTE; + eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT; + GPUTexture *texture = GPU_texture_create_2d( + "seq_display_buf", scope_image->x, scope_image->y, 1, format, usage, nullptr); + GPU_texture_update(texture, data, scope_image->byte_buffer.data); + GPU_texture_filter_mode(texture, false); + + GPU_texture_bind(texture, 0); + + GPUVertFormat *imm_format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(imm_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + uint texCoord = GPU_vertformat_attr_add( + imm_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_COLOR); + immUniformColor3f(1.0f, 1.0f, 1.0f); + + immBegin(GPU_PRIM_TRI_FAN, 4); + + immAttr2f(texCoord, canvas.xmin, canvas.ymin); + immVertex2f(pos, preview.xmin, preview.ymin); + + immAttr2f(texCoord, canvas.xmin, canvas.ymax); + immVertex2f(pos, preview.xmin, preview.ymax); + + immAttr2f(texCoord, canvas.xmax, canvas.ymax); + immVertex2f(pos, preview.xmax, preview.ymax); + + immAttr2f(texCoord, canvas.xmax, canvas.ymin); + immVertex2f(pos, preview.xmax, preview.ymin); + + immEnd(); + + GPU_texture_unbind(texture); + GPU_texture_free(texture); + + immUnbindProgram(); + } + + uchar col_bg[4] = {0, 0, 0, 255}; + uchar col_border[4] = {0, 160, 0, 255}; + if (scope_image == nullptr) { + quads.add_quad(preview.xmin, preview.ymin, preview.xmax, preview.ymax, col_bg); + } + + if (sseq->mainb == SEQ_DRAW_IMG_HISTOGRAM) { + draw_histogram(scopes->histogram, quads, preview); + } + + if (scope_image == nullptr) { + quads.add_wire_quad(preview.xmin, preview.ymin, preview.xmax, preview.ymax, col_border); + } + quads.draw(); + + if (use_blend) { + GPU_blend(GPU_BLEND_NONE); + } +} + +static bool sequencer_calc_scopes(Scene *scene, SpaceSeq *sseq, ImBuf *ibuf, bool draw_backdrop) +{ + using namespace blender::ed::seq; + + if (draw_backdrop || (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->zebra == 0)) { + return false; /* Not drawing any scopes. */ + } + + SeqScopes *scopes = &sseq->runtime->scopes; + if (scopes->reference_ibuf != ibuf) { + scopes->cleanup(); + } + + switch (sseq->mainb) { + case SEQ_DRAW_IMG_IMBUF: + if (!scopes->zebra_ibuf) { + + if (ibuf->float_buffer.data) { + ImBuf *display_ibuf = IMB_dupImBuf(ibuf); + IMB_colormanagement_imbuf_make_display_space( + display_ibuf, &scene->view_settings, &scene->display_settings); + scopes->zebra_ibuf = make_zebra_view_from_ibuf(display_ibuf, sseq->zebra); + IMB_freeImBuf(display_ibuf); + } + else { + scopes->zebra_ibuf = make_zebra_view_from_ibuf(ibuf, sseq->zebra); + } + } + break; + case SEQ_DRAW_IMG_WAVEFORM: + if ((sseq->flag & SEQ_DRAW_COLOR_SEPARATED) != 0) { + if (!scopes->sep_waveform_ibuf) { + scopes->sep_waveform_ibuf = sequencer_make_scope( + scene, ibuf, make_sep_waveform_view_from_ibuf); + } + } + else { + if (!scopes->waveform_ibuf) { + scopes->waveform_ibuf = sequencer_make_scope(scene, ibuf, make_waveform_view_from_ibuf); + } + } + break; + case SEQ_DRAW_IMG_VECTORSCOPE: + if (!scopes->vector_ibuf) { + scopes->vector_ibuf = sequencer_make_scope(scene, ibuf, make_vectorscope_view_from_ibuf); + } + break; + case SEQ_DRAW_IMG_HISTOGRAM: { + ImBuf *display_ibuf = IMB_dupImBuf(ibuf); + IMB_colormanagement_imbuf_make_display_space( + display_ibuf, &scene->view_settings, &scene->display_settings); + scopes->histogram.calc_from_ibuf(display_ibuf); + IMB_freeImBuf(display_ibuf); + } break; + default: /* Future files might have scopes we don't know about. */ + return false; + } + scopes->reference_ibuf = ibuf; + return true; } bool sequencer_draw_get_transform_preview(SpaceSeq *sseq, Scene *scene) @@ -732,7 +839,6 @@ void sequencer_draw_preview(const bContext *C, Depsgraph *depsgraph = CTX_data_expect_evaluated_depsgraph(C); View2D *v2d = ®ion->v2d; ImBuf *ibuf = nullptr; - ImBuf *scope = nullptr; float viewrect[2]; const bool show_imbuf = ED_space_sequencer_check_show_imbuf(sseq); const bool draw_gpencil = ((sseq->preview_overlay.flag & SEQ_PREVIEW_SHOW_GPENCIL) && sseq->gpd); @@ -781,13 +887,17 @@ void sequencer_draw_preview(const bContext *C, } if (ibuf) { - scope = sequencer_get_scope(scene, sseq, ibuf, draw_backdrop); + bool has_scope = sequencer_calc_scopes(scene, sseq, ibuf, draw_backdrop); + if (has_scope) { + /* Draw scope. */ + sequencer_draw_scopes(scene, region, sseq, draw_overlay); + } + else { + /* Draw image. */ + sequencer_draw_display_buffer(C, scene, region, sseq, ibuf, draw_overlay, draw_backdrop); + } - /* Draw image. */ - sequencer_draw_display_buffer( - C, scene, region, sseq, ibuf, scope, draw_overlay, draw_backdrop); - - /* Draw over image. */ + /* Draw metadata. */ if (sseq->preview_overlay.flag & SEQ_PREVIEW_SHOW_METADATA && sseq->flag & SEQ_SHOW_OVERLAY) { ED_region_image_metadata_draw(0.0, 0.0, ibuf, &v2d->tot, 1.0, 1.0); } @@ -821,7 +931,6 @@ void sequencer_draw_preview(const bContext *C, ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW); GPU_framebuffer_bind_no_srgb(framebuffer_overlay); - /* Scope is freed in sequencer_check_scopes when `ibuf` changes and redraw is needed. */ if (ibuf) { IMB_freeImBuf(ibuf); } diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.cc b/source/blender/editors/space_sequencer/sequencer_scopes.cc index a35d9d6021e..0b55eb6c189 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.cc +++ b/source/blender/editors/space_sequencer/sequencer_scopes.cc @@ -9,6 +9,7 @@ #include #include +#include "BLI_math_vector.hh" #include "BLI_task.h" #include "BLI_task.hh" #include "BLI_utildefines.h" @@ -25,23 +26,32 @@ # include "BLI_timeit.hh" #endif -SequencerScopes::~SequencerScopes() +namespace blender::ed::seq { + +SeqScopes::~SeqScopes() +{ + cleanup(); +} + +void SeqScopes::cleanup() { if (zebra_ibuf) { IMB_freeImBuf(zebra_ibuf); + zebra_ibuf = nullptr; } if (waveform_ibuf) { IMB_freeImBuf(waveform_ibuf); + waveform_ibuf = nullptr; } if (sep_waveform_ibuf) { IMB_freeImBuf(sep_waveform_ibuf); + sep_waveform_ibuf = nullptr; } if (vector_ibuf) { IMB_freeImBuf(vector_ibuf); + vector_ibuf = nullptr; } - if (histogram_ibuf) { - IMB_freeImBuf(histogram_ibuf); - } + histogram.data.reinitialize(0); } /* XXX(@ideasman42): why is this function better than BLI_math version? @@ -459,127 +469,7 @@ ImBuf *make_zebra_view_from_ibuf(ImBuf *ibuf, float perc) return new_ibuf; } -static void draw_histogram_marker(ImBuf *ibuf, int x) -{ - uchar *p = ibuf->byte_buffer.data; - int barh = ibuf->y * 0.1; - - p += 4 * (x + ibuf->x * (ibuf->y - barh + 1)); - - for (int i = 0; i < barh - 1; i++) { - p[0] = p[1] = p[2] = 255; - p += ibuf->x * 4; - } -} - -static void draw_histogram_bar(ImBuf *ibuf, int x, float val, int col) -{ - uchar *p = ibuf->byte_buffer.data; - int barh = ibuf->y * val * 0.9f; - - p += 4 * (x + ibuf->x); - - for (int i = 0; i < barh; i++) { - p[col] = 255; - p += ibuf->x * 4; - } -} - -#define HIS_STEPS 512 - -struct MakeHistogramViewData { - const ImBuf *ibuf; -}; - -static void make_histogram_view_from_ibuf_byte_fn(void *__restrict userdata, - const int y, - const TaskParallelTLS *__restrict tls) -{ - const MakeHistogramViewData *data = static_cast(userdata); - const ImBuf *ibuf = data->ibuf; - const uchar *src = ibuf->byte_buffer.data; - - uint32_t(*cur_bins)[HIS_STEPS] = static_cast(tls->userdata_chunk); - - for (int x = 0; x < ibuf->x; x++) { - const uchar *pixel = src + (y * ibuf->x + x) * 4; - - for (int j = 3; j--;) { - cur_bins[j][pixel[j]]++; - } - } -} - -static void make_histogram_view_from_ibuf_reduce(const void *__restrict /*userdata*/, - void *__restrict chunk_join, - void *__restrict chunk) -{ - uint32_t(*join_bins)[HIS_STEPS] = static_cast(chunk_join); - uint32_t(*bins)[HIS_STEPS] = static_cast(chunk); - for (int j = 3; j--;) { - for (int i = 0; i < HIS_STEPS; i++) { - join_bins[j][i] += bins[j][i]; - } - } -} - -static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf) -{ -#ifdef DEBUG_TIME - SCOPED_TIMER_AVERAGED(__func__); -#endif - ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect); - int x; - uint nr, ng, nb; - - uint bins[3][HIS_STEPS]; - - memset(bins, 0, sizeof(bins)); - - MakeHistogramViewData data{}; - data.ibuf = ibuf; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (ibuf->y >= 256); - settings.userdata_chunk = bins; - settings.userdata_chunk_size = sizeof(bins); - settings.func_reduce = make_histogram_view_from_ibuf_reduce; - BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_byte_fn, &settings); - - nr = nb = ng = 0; - for (x = 0; x < HIS_STEPS; x++) { - if (bins[0][x] > nr) { - nr = bins[0][x]; - } - if (bins[1][x] > ng) { - ng = bins[1][x]; - } - if (bins[2][x] > nb) { - nb = bins[2][x]; - } - } - - for (x = 0; x < HIS_STEPS; x++) { - if (nr) { - draw_histogram_bar(rval, x * 2 + 1, float(bins[0][x]) / nr, 0); - draw_histogram_bar(rval, x * 2 + 2, float(bins[0][x]) / nr, 0); - } - if (ng) { - draw_histogram_bar(rval, x * 2 + 1, float(bins[1][x]) / ng, 1); - draw_histogram_bar(rval, x * 2 + 2, float(bins[1][x]) / ng, 1); - } - if (nb) { - draw_histogram_bar(rval, x * 2 + 1, float(bins[2][x]) / nb, 2); - draw_histogram_bar(rval, x * 2 + 2, float(bins[2][x]) / nb, 2); - } - } - - wform_put_border(rval->byte_buffer.data, rval->x, rval->y); - - return rval; -} - -BLI_INLINE int get_bin_float(float f) +static int get_bin_float(float f) { if (f < -0.25f) { return 0; @@ -587,92 +477,65 @@ BLI_INLINE int get_bin_float(float f) if (f >= 1.25f) { return 511; } - return int(((f + 0.25f) / 1.5f) * 512); } -static void make_histogram_view_from_ibuf_float_fn(void *__restrict userdata, - const int y, - const TaskParallelTLS *__restrict tls) -{ - const MakeHistogramViewData *data = static_cast(userdata); - const ImBuf *ibuf = static_cast(data->ibuf); - const float *src = ibuf->float_buffer.data; - - uint32_t(*cur_bins)[HIS_STEPS] = static_cast(tls->userdata_chunk); - - for (int x = 0; x < ibuf->x; x++) { - const float *pixel = src + (y * ibuf->x + x) * 4; - - for (int j = 3; j--;) { - cur_bins[j][get_bin_float(pixel[j])]++; - } - } -} - -static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf) +void ScopeHistogram::calc_from_ibuf(const ImBuf *ibuf) { #ifdef DEBUG_TIME SCOPED_TIMER_AVERAGED(__func__); #endif - ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect); - int nr, ng, nb; - int x; - uint bins[3][HIS_STEPS]; + const bool is_float = ibuf->float_buffer.data != nullptr; + const int hist_size = is_float ? 512 : 256; - memset(bins, 0, sizeof(bins)); + Array counts(hist_size, uint3(0)); + data = threading::parallel_reduce( + IndexRange(ibuf->y), + 256, + counts, + [&](const IndexRange y_range, const Array &init) { + Array res = init; - MakeHistogramViewData data{}; - data.ibuf = ibuf; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (ibuf->y >= 256); - settings.userdata_chunk = bins; - settings.userdata_chunk_size = sizeof(bins); - settings.func_reduce = make_histogram_view_from_ibuf_reduce; - BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_float_fn, &settings); + if (is_float) { + /* Float images spead -0.25..+1.25 range over 512 bins. */ + for (const int y : y_range) { + const float *src = ibuf->float_buffer.data + y * ibuf->x * 4; + for (int x = 0; x < ibuf->x; x++) { + res[get_bin_float(src[0])].x++; + res[get_bin_float(src[1])].y++; + res[get_bin_float(src[2])].z++; + src += 4; + } + } + } + else { + /* Byte images just use 256 histogram bins, directly indexed by value. */ + for (const int y : y_range) { + const uchar *src = ibuf->byte_buffer.data + y * ibuf->x * 4; + for (int x = 0; x < ibuf->x; x++) { + res[src[0]].x++; + res[src[1]].y++; + res[src[2]].z++; + src += 4; + } + } + } + return res; + }, + [&](const Array &a, const Array &b) { + BLI_assert(a.size() == b.size()); + Array res(a.size()); + for (int i = 0; i < a.size(); i++) { + res[i] = a[i] + b[i]; + } + return res; + }); - nr = nb = ng = 0; - for (x = 0; x < HIS_STEPS; x++) { - if (bins[0][x] > nr) { - nr = bins[0][x]; - } - if (bins[1][x] > ng) { - ng = bins[1][x]; - } - if (bins[2][x] > nb) { - nb = bins[2][x]; - } + max_value = uint3(0); + for (const uint3 &v : data) { + max_value = math::max(max_value, v); } - - for (x = 0; x < HIS_STEPS; x++) { - if (nr) { - draw_histogram_bar(rval, x + 1, float(bins[0][x]) / nr, 0); - } - if (ng) { - draw_histogram_bar(rval, x + 1, float(bins[1][x]) / ng, 1); - } - if (nb) { - draw_histogram_bar(rval, x + 1, float(bins[2][x]) / nb, 2); - } - } - - draw_histogram_marker(rval, get_bin_float(0.0)); - draw_histogram_marker(rval, get_bin_float(1.0)); - wform_put_border(rval->byte_buffer.data, rval->x, rval->y); - - return rval; -} - -#undef HIS_STEPS - -ImBuf *make_histogram_view_from_ibuf(ImBuf *ibuf) -{ - if (ibuf->float_buffer.data) { - return make_histogram_view_from_ibuf_float(ibuf); - } - return make_histogram_view_from_ibuf_byte(ibuf); } static void vectorscope_put_cross(uchar r, uchar g, uchar b, uchar *tgt, int w, int h, int size) @@ -806,3 +669,5 @@ ImBuf *make_vectorscope_view_from_ibuf(ImBuf *ibuf) } return make_vectorscope_view_from_ibuf_byte(ibuf); } + +} // namespace blender::ed::seq diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.hh b/source/blender/editors/space_sequencer/sequencer_scopes.hh index ab6721a490c..293d79551b6 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.hh +++ b/source/blender/editors/space_sequencer/sequencer_scopes.hh @@ -8,24 +8,40 @@ #pragma once +#include "BLI_array.hh" +#include "BLI_math_vector_types.hh" + struct ImBuf; -struct SequencerScopes { - SequencerScopes() = default; - ~SequencerScopes(); - SequencerScopes(const SequencerScopes &) = delete; - void operator=(const SequencerScopes &) = delete; +namespace blender::ed::seq { + +struct ScopeHistogram { + Array data; + uint3 max_value; + + void calc_from_ibuf(const ImBuf *ibuf); +}; + +struct SeqScopes { + SeqScopes() = default; + ~SeqScopes(); + SeqScopes(const SeqScopes &) = delete; + void operator=(const SeqScopes &) = delete; + + void cleanup(); ImBuf *reference_ibuf = nullptr; ImBuf *zebra_ibuf = nullptr; ImBuf *waveform_ibuf = nullptr; ImBuf *sep_waveform_ibuf = nullptr; ImBuf *vector_ibuf = nullptr; - ImBuf *histogram_ibuf = nullptr; + + ScopeHistogram histogram; }; ImBuf *make_waveform_view_from_ibuf(ImBuf *ibuf); ImBuf *make_sep_waveform_view_from_ibuf(ImBuf *ibuf); ImBuf *make_vectorscope_view_from_ibuf(ImBuf *ibuf); ImBuf *make_zebra_view_from_ibuf(ImBuf *ibuf, float perc); -ImBuf *make_histogram_view_from_ibuf(ImBuf *ibuf); + +} // namespace blender::ed::seq -- 2.30.2 From a581d73da7e4c8d343d51b3c68e20a0ce03d8736 Mon Sep 17 00:00:00 2001 From: Aras Pranckevicius Date: Thu, 4 Jan 2024 13:52:09 +0200 Subject: [PATCH 04/11] VSE: tweak the look of Waveform display (draw grid as actual lines, tweak gamma, etc) --- .../space_sequencer/sequencer_preview_draw.cc | 33 ++- .../space_sequencer/sequencer_scopes.cc | 214 ++++-------------- 2 files changed, 71 insertions(+), 176 deletions(-) diff --git a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc index f92bbdfe605..58911fb148a 100644 --- a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc +++ b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc @@ -522,9 +522,12 @@ static void draw_histogram(const blender::ed::seq::ScopeHistogram &hist, return; } - uchar col_grid[4] = {128, 128, 128, 128}; + /* Background. */ + uchar col_bg[4] = {0, 0, 0, 255}; + quads.add_quad(area.xmin, area.ymin, area.xmax, area.ymax, col_bg); /* Grid lines. */ + uchar col_grid[4] = {128, 128, 128, 128}; float grid_x_0 = area.xmin; float grid_x_1 = area.xmax; if (hist.data.size() > 256) { @@ -536,6 +539,10 @@ static void draw_histogram(const blender::ed::seq::ScopeHistogram &hist, quads.add_line(x, area.ymin, x, area.ymax, col_grid); } + /* Border. */ + uchar col_border[4] = {64, 64, 64, 128}; + quads.add_wire_quad(area.xmin, area.ymin, area.xmax, area.ymax, col_border); + /* Histogram area & line for each R/G/B channels, additively blended. */ quads.draw(); GPU_blend(GPU_BLEND_ADDITIVE); @@ -648,19 +655,25 @@ static void sequencer_draw_scopes(Scene *scene, ARegion *region, SpaceSeq *sseq, immUnbindProgram(); } - uchar col_bg[4] = {0, 0, 0, 255}; - uchar col_border[4] = {0, 160, 0, 255}; - if (scope_image == nullptr) { - quads.add_quad(preview.xmin, preview.ymin, preview.xmax, preview.ymax, col_bg); - } - if (sseq->mainb == SEQ_DRAW_IMG_HISTOGRAM) { draw_histogram(scopes->histogram, quads, preview); } - - if (scope_image == nullptr) { - quads.add_wire_quad(preview.xmin, preview.ymin, preview.xmax, preview.ymax, col_border); + if (sseq->mainb == SEQ_DRAW_IMG_WAVEFORM) { + /* Horizontal lines at 10%, 70%, 90%. */ + uchar col_grid[4] = {160, 64, 64, 128}; + const float x0 = preview.xmin; + const float x1 = preview.xmax; + const float y10 = preview.ymin + (preview.ymax - preview.ymin) * 0.10f; + const float y70 = preview.ymin + (preview.ymax - preview.ymin) * 0.70f; + const float y90 = preview.ymin + (preview.ymax - preview.ymin) * 0.90f; + quads.add_line(x0, y10, x1, y10, col_grid); + quads.add_line(x0, y70, x1, y70, col_grid); + quads.add_line(x0, y90, x1, y90, col_grid); + /* Border. */ + uchar col_border[4] = {64, 64, 64, 128}; + quads.add_wire_quad(x0, preview.ymin, x1, preview.ymax, col_border); } + quads.draw(); if (use_blend) { diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.cc b/source/blender/editors/space_sequencer/sequencer_scopes.cc index 0b55eb6c189..4f51112380b 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.cc +++ b/source/blender/editors/space_sequencer/sequencer_scopes.cc @@ -79,84 +79,32 @@ static void scope_put_pixel(const uchar *table, uchar *pos) static void scope_put_pixel_single(const uchar *table, uchar *pos, int col) { - char newval = table[pos[col]]; - pos[col] = newval; + uint newval = table[pos[col]]; + /* So that the separate waveforms are not just pure RGB primaries, put + * some amount of value into the other channels too: slightly reduce it, + * and raise to 4th power. */ + uint other = newval * 31 / 32; + other = (other * other) >> 8; + other = (other * other) >> 8; + pos[0] = pos[1] = pos[2] = uchar(other); + pos[col] = uchar(newval); pos[3] = 255; } -static void wform_put_line(int w, uchar *last_pos, uchar *new_pos) +static void init_wave_table(int height, uchar wtable[256]) { - if (last_pos > new_pos) { - uchar *temp = new_pos; - new_pos = last_pos; - last_pos = temp; + /* For each pixel column of the image, waveform plots the intensity values + * with height proportional to the intensity. So depending on the height of + * the image, different amount of pixels are expected to hit the same + * intensity. Adjust the waveform plotting table gamma factor so that + * the waveform has decent visibility without saturating or being too dark: + * 0.3 gamma at height=360 and below, 0.9 gamma at height 2160 (4K) and up, + * and interpolating between those. */ + float alpha = clamp_f(ratiof(360.0f, 2160.0f, height), 0.0f, 1.0f); + float gamma = interpf(0.9f, 0.3f, alpha); + for (int x = 0; x < 256; x++) { + wtable[x] = uchar(pow((float(x) + 1.0f) / 256.0f, gamma) * 255.0f); } - - while (last_pos < new_pos) { - if (last_pos[0] == 0) { - last_pos[0] = last_pos[1] = last_pos[2] = 32; - last_pos[3] = 255; - } - last_pos += 4 * w; - } -} - -static void wform_put_line_single(int w, uchar *last_pos, uchar *new_pos, int col) -{ - if (last_pos > new_pos) { - uchar *temp = new_pos; - new_pos = last_pos; - last_pos = temp; - } - - while (last_pos < new_pos) { - if (last_pos[col] == 0) { - last_pos[col] = 32; - last_pos[3] = 255; - } - last_pos += 4 * w; - } -} - -static void wform_put_border(uchar *tgt, int w, int h) -{ - int x, y; - - for (x = 0; x < w; x++) { - uchar *p = tgt + 4 * x; - p[1] = p[3] = 155; - p[4 * w + 1] = p[4 * w + 3] = 155; - p = tgt + 4 * (w * (h - 1) + x); - p[1] = p[3] = 155; - p[-4 * w + 1] = p[-4 * w + 3] = 155; - } - - for (y = 0; y < h; y++) { - uchar *p = tgt + 4 * w * y; - p[1] = p[3] = 155; - p[4 + 1] = p[4 + 3] = 155; - p = tgt + 4 * (w * y + w - 1); - p[1] = p[3] = 155; - p[-4 + 1] = p[-4 + 3] = 155; - } -} - -static void wform_put_gridrow(uchar *tgt, float perc, int w, int h) -{ - tgt += int(perc / 100.0f * h) * w * 4; - - for (int i = 0; i < w * 2; i++) { - tgt[0] = 255; - - tgt += 4; - } -} - -static void wform_put_grid(uchar *tgt, int w, int h) -{ - wform_put_gridrow(tgt, 90.0, w, h); - wform_put_gridrow(tgt, 70.0, w, h); - wform_put_gridrow(tgt, 10.0, w, h); } static ImBuf *make_waveform_view_from_ibuf_byte(ImBuf *ibuf) @@ -165,20 +113,14 @@ static ImBuf *make_waveform_view_from_ibuf_byte(ImBuf *ibuf) SCOPED_TIMER_AVERAGED(__func__); #endif using namespace blender; - ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect); + int w = ibuf->x; + int h = 256; + ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect); const uchar *src = ibuf->byte_buffer.data; uchar *tgt = rval->byte_buffer.data; - int w = ibuf->x + 3; - int h = 515; - float waveform_gamma = 0.2; + uchar wtable[256]; - - wform_put_grid(tgt, w, h); - wform_put_border(tgt, w, h); - - for (int x = 0; x < 256; x++) { - wtable[x] = uchar(pow((float(x) + 1.0f) / 256.0f, waveform_gamma) * 255.0f); - } + init_wave_table(ibuf->y, wtable); /* IMB_colormanagement_get_luminance_byte for each pixel is quite a lot of * overhead, so instead get luma coefficients as 16-bit integers. */ @@ -189,7 +131,6 @@ static ImBuf *make_waveform_view_from_ibuf_byte(ImBuf *ibuf) /* Parallel over x, since each column is easily independent from others. */ threading::parallel_for(IndexRange(ibuf->x), 16, [&](IndexRange x_range) { for (int y = 0; y < ibuf->y; y++) { - uchar *last_p = nullptr; for (const int x : x_range) { const uchar *rgb = src + 4 * (ibuf->x * y + x); @@ -198,17 +139,9 @@ static ImBuf *make_waveform_view_from_ibuf_byte(ImBuf *ibuf) int rgb1 = rgb[1] + 1; int rgb2 = rgb[2] + 1; int luma = (rgb0 * muls[0] + rgb1 * muls[1] + rgb2 * muls[2]) >> 16; - int luma_y = clamp_i(luma, 0, 255) * 2; - uchar *p = tgt + 4 * (w * (luma_y + 1) + x + 1); - + int luma_y = clamp_i(luma, 0, 255); + uchar *p = tgt + 4 * (w * luma_y + x); scope_put_pixel(wtable, p); - p += 4 * w; - scope_put_pixel(wtable, p); - - if (last_p != nullptr) { - wform_put_line(w, last_p, p); - } - last_p = p; } } }); @@ -222,48 +155,32 @@ static ImBuf *make_waveform_view_from_ibuf_float(ImBuf *ibuf) SCOPED_TIMER_AVERAGED(__func__); #endif using namespace blender; - ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect); + int w = ibuf->x; + int h = 256; + ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect); const float *src = ibuf->float_buffer.data; uchar *tgt = rval->byte_buffer.data; - int w = ibuf->x + 3; - int h = 515; - float waveform_gamma = 0.2; + uchar wtable[256]; - - wform_put_grid(tgt, w, h); - - for (int x = 0; x < 256; x++) { - wtable[x] = uchar(pow((float(x) + 1.0f) / 256.0f, waveform_gamma) * 255.0f); - } + init_wave_table(ibuf->y, wtable); /* Parallel over x, since each column is easily independent from others. */ threading::parallel_for(IndexRange(ibuf->x), 16, [&](IndexRange x_range) { for (int y = 0; y < ibuf->y; y++) { - uchar *last_p = nullptr; for (const int x : x_range) { const float *rgb = src + 4 * (ibuf->x * y + x); float v = IMB_colormanagement_get_luminance(rgb); uchar *p = tgt; - CLAMP(v, 0.0f, 1.0f); - - p += 4 * (w * (int(v * (h - 3)) + 1) + x + 1); + int iv = clamp_i(int(v * h), 0, h - 1); + p += 4 * (w * iv + x); scope_put_pixel(wtable, p); - p += 4 * w; - scope_put_pixel(wtable, p); - - if (last_p != nullptr) { - wform_put_line(w, last_p, p); - } - last_p = p; } } }); - wform_put_border(tgt, w, h); - return rval; } @@ -281,48 +198,31 @@ static ImBuf *make_sep_waveform_view_from_ibuf_byte(ImBuf *ibuf) SCOPED_TIMER_AVERAGED(__func__); #endif using namespace blender; - ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect); + int w = ibuf->x; + int h = 256; + ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect); const uchar *src = ibuf->byte_buffer.data; uchar *tgt = rval->byte_buffer.data; - int w = ibuf->x + 3; int sw = ibuf->x / 3; - int h = 515; - float waveform_gamma = 0.2; + uchar wtable[256]; - - wform_put_grid(tgt, w, h); - - for (int x = 0; x < 256; x++) { - wtable[x] = uchar(pow((float(x) + 1.0f) / 256.0f, waveform_gamma) * 255.0f); - } + init_wave_table(ibuf->y, wtable); /* Parallel over x, since each column is easily independent from others. */ threading::parallel_for(IndexRange(ibuf->x), 16, [&](IndexRange x_range) { for (int y = 0; y < ibuf->y; y++) { - uchar *last_p[3] = {nullptr, nullptr, nullptr}; - for (const int x : x_range) { int c; const uchar *rgb = src + 4 * (ibuf->x * y + x); for (c = 0; c < 3; c++) { uchar *p = tgt; - p += 4 * (w * (rgb[c] * 2 + 1) + c * sw + x / 3 + 1); - + p += 4 * (w * rgb[c] + c * sw + x / 3); scope_put_pixel_single(wtable, p, c); - p += 4 * w; - scope_put_pixel_single(wtable, p, c); - - if (last_p[c] != nullptr) { - wform_put_line_single(w, last_p[c], p, c); - } - last_p[c] = p; } } } }); - wform_put_border(tgt, w, h); - return rval; } @@ -332,52 +232,34 @@ static ImBuf *make_sep_waveform_view_from_ibuf_float(ImBuf *ibuf) SCOPED_TIMER_AVERAGED(__func__); #endif using namespace blender; - ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect); + int w = ibuf->x; + int h = 256; + ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect); const float *src = ibuf->float_buffer.data; uchar *tgt = rval->byte_buffer.data; - int w = ibuf->x + 3; int sw = ibuf->x / 3; - int h = 515; - float waveform_gamma = 0.2; + uchar wtable[256]; - - wform_put_grid(tgt, w, h); - - for (int x = 0; x < 256; x++) { - wtable[x] = uchar(pow((float(x) + 1.0f) / 256.0f, waveform_gamma) * 255.0f); - } + init_wave_table(ibuf->y, wtable); /* Parallel over x, since each column is easily independent from others. */ threading::parallel_for(IndexRange(ibuf->x), 16, [&](IndexRange x_range) { for (int y = 0; y < ibuf->y; y++) { - uchar *last_p[3] = {nullptr, nullptr, nullptr}; - for (const int x : x_range) { int c; const float *rgb = src + 4 * (ibuf->x * y + x); for (c = 0; c < 3; c++) { uchar *p = tgt; float v = rgb[c]; + int iv = clamp_i(int(v * h), 0, h - 1); - CLAMP(v, 0.0f, 1.0f); - - p += 4 * (w * (int(v * (h - 3)) + 1) + c * sw + x / 3 + 1); - + p += 4 * (w * iv + c * sw + x / 3); scope_put_pixel_single(wtable, p, c); - p += 4 * w; - scope_put_pixel_single(wtable, p, c); - - if (last_p[c] != nullptr) { - wform_put_line_single(w, last_p[c], p, c); - } - last_p[c] = p; } } } }); - wform_put_border(tgt, w, h); - return rval; } -- 2.30.2 From 6767dc2b393bd039a21404033314916e97ec6159 Mon Sep 17 00:00:00 2001 From: Aras Pranckevicius Date: Thu, 4 Jan 2024 19:12:26 +0200 Subject: [PATCH 05/11] VSE: improve Vectorscope - RGB -> YUV conversion uses BT709 (just like image vectorscope), instead of "something similar but not quite". - It now has square aspect ratio. - Shows skin tone line, just like image vectorscope. - Shows full saturation and "safe" saturation range as filled area, drawing that on the GPU instead of poking in the full saturation ring on the CPU into the texture. --- .../space_sequencer/sequencer_preview_draw.cc | 98 ++++++++++++++++-- .../space_sequencer/sequencer_quads_batch.cc | 17 ++-- .../space_sequencer/sequencer_quads_batch.hh | 22 ++++- .../space_sequencer/sequencer_scopes.cc | 99 ++++--------------- 4 files changed, 141 insertions(+), 95 deletions(-) diff --git a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc index 58911fb148a..574388b6b21 100644 --- a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc +++ b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc @@ -10,6 +10,7 @@ #include #include "BLI_blenlib.h" +#include "BLI_math_rotation.h" #include "BLI_utildefines.h" #include "IMB_imbuf_types.h" @@ -571,20 +572,98 @@ static void draw_histogram(const blender::ed::seq::ScopeHistogram &hist, GPU_blend(GPU_BLEND_ALPHA); } +static blender::float2 rgb_to_uv(const blender::float3 &rgb) +{ + float y, u, v; + rgb_to_yuv(rgb.x, rgb.y, rgb.z, &y, &u, &v, BLI_YUV_ITU_BT709); + return blender::float2(u, v); +} + +static void draw_vectorscope_graticule(SeqQuadsBatch &quads, const rctf &area) +{ + using namespace blender; + GPU_blend(GPU_BLEND_ALPHA); + + const float skin_rad = DEG2RADF(123.0f); /* angle in radians of the skin tone line */ + + const float w = BLI_rctf_size_x(&area); + const float h = BLI_rctf_size_y(&area); + const float centerx = BLI_rctf_cent_x(&area); + const float centery = BLI_rctf_cent_y(&area); + const float radius = ((w < h) ? w : h) * 0.5f * (0.5f / 0.615f); + + /* center cross */ + uchar col_grid[4] = {128, 128, 128, 96}; + quads.add_line(centerx - radius * 0.1f, centery, centerx + radius * 0.1f, centery, col_grid); + quads.add_line(centerx, centery - radius * 0.1f, centerx, centery + radius * 0.1f, col_grid); + + /* fully saturated vs "safe" (0.75) colored areas */ + quads.draw(); + GPU_blend(GPU_BLEND_ADDITIVE); + const float3 primaries[6] = { + {1, 0, 0}, + {1, 1, 0}, + {0, 1, 0}, + {0, 1, 1}, + {0, 0, 1}, + {1, 0, 1}, + }; + float2 center{centerx, centery}; + for (int i = 0; i < 6; i++) { + float3 prim0 = primaries[i]; + float3 prim1 = primaries[(i + 1) % 6]; + float3 safe0 = prim0 * 0.75f; + float3 safe1 = prim1 * 0.75f; + float2 uv0 = center + rgb_to_uv(prim0) * (radius * 2); + float2 uv1 = center + rgb_to_uv(prim1) * (radius * 2); + float2 uv2 = center + rgb_to_uv(safe0) * (radius * 2); + float2 uv3 = center + rgb_to_uv(safe1) * (radius * 2); + uchar col0[4] = {uchar(prim0.x * 255), uchar(prim0.y * 255), uchar(prim0.z * 255), 128}; + uchar col1[4] = {uchar(prim1.x * 255), uchar(prim1.y * 255), uchar(prim1.z * 255), 128}; + uchar col2[4] = {uchar(safe0.x * 255), uchar(safe0.y * 255), uchar(safe0.z * 255), 128}; + uchar col3[4] = {uchar(safe1.x * 255), uchar(safe1.y * 255), uchar(safe1.z * 255), 128}; + quads.add_quad(uv0.x, uv0.y, uv1.x, uv1.y, uv2.x, uv2.y, uv3.x, uv3.y, col0, col1, col2, col3); + } + quads.draw(); + GPU_blend(GPU_BLEND_ALPHA); + + /* skin tone line */ + uchar col_tone[4] = {255, 102, 0, 128}; + const float tone_line_len = radius * 0.895f; /* makes it end at outer edge of saturation ring */ + quads.add_line(centerx, + centery, + centerx + cosf(skin_rad) * tone_line_len, + centery + sinf(skin_rad) * tone_line_len, + col_tone); +} + static void sequencer_draw_scopes(Scene *scene, ARegion *region, SpaceSeq *sseq, bool draw_overlay) { using namespace blender::ed::seq; /* Figure out draw coordinates. */ rctf preview; - rctf canvas; sequencer_preview_get_rect(&preview, scene, region, sseq, draw_overlay, false); + rctf uv; if (draw_overlay && (sseq->overlay_frame_type == SEQ_OVERLAY_FRAME_TYPE_RECT)) { - canvas = scene->ed->overlay_frame_rect; + uv = scene->ed->overlay_frame_rect; } else { - BLI_rctf_init(&canvas, 0.0f, 1.0f, 0.0f, 1.0f); + BLI_rctf_init(&uv, 0.0f, 1.0f, 0.0f, 1.0f); + } + const bool keep_aspect = sseq->mainb == SEQ_DRAW_IMG_VECTORSCOPE; + float vecscope_aspect = 1.0f; + if (keep_aspect) { + float width = std::max(BLI_rctf_size_x(&preview), 0.1f); + float height = std::max(BLI_rctf_size_y(&preview), 0.1f); + vecscope_aspect = width / height; + if (vecscope_aspect >= 1.0f) { + BLI_rctf_resize_x(&uv, BLI_rctf_size_x(&uv) * vecscope_aspect); + } + else { + BLI_rctf_resize_y(&uv, BLI_rctf_size_y(&uv) / vecscope_aspect); + } } SeqQuadsBatch quads; @@ -623,6 +702,7 @@ static void sequencer_draw_scopes(Scene *scene, ARegion *region, SpaceSeq *sseq, "seq_display_buf", scope_image->x, scope_image->y, 1, format, usage, nullptr); GPU_texture_update(texture, data, scope_image->byte_buffer.data); GPU_texture_filter_mode(texture, false); + GPU_texture_extend_mode(texture, GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER); GPU_texture_bind(texture, 0); @@ -635,16 +715,16 @@ static void sequencer_draw_scopes(Scene *scene, ARegion *region, SpaceSeq *sseq, immBegin(GPU_PRIM_TRI_FAN, 4); - immAttr2f(texCoord, canvas.xmin, canvas.ymin); + immAttr2f(texCoord, uv.xmin, uv.ymin); immVertex2f(pos, preview.xmin, preview.ymin); - immAttr2f(texCoord, canvas.xmin, canvas.ymax); + immAttr2f(texCoord, uv.xmin, uv.ymax); immVertex2f(pos, preview.xmin, preview.ymax); - immAttr2f(texCoord, canvas.xmax, canvas.ymax); + immAttr2f(texCoord, uv.xmax, uv.ymax); immVertex2f(pos, preview.xmax, preview.ymax); - immAttr2f(texCoord, canvas.xmax, canvas.ymin); + immAttr2f(texCoord, uv.xmax, uv.ymin); immVertex2f(pos, preview.xmax, preview.ymin); immEnd(); @@ -673,6 +753,10 @@ static void sequencer_draw_scopes(Scene *scene, ARegion *region, SpaceSeq *sseq, uchar col_border[4] = {64, 64, 64, 128}; quads.add_wire_quad(x0, preview.ymin, x1, preview.ymax, col_border); } + if (sseq->mainb == SEQ_DRAW_IMG_VECTORSCOPE) { + use_blend = true; + draw_vectorscope_graticule(quads, preview); + } quads.draw(); diff --git a/source/blender/editors/space_sequencer/sequencer_quads_batch.cc b/source/blender/editors/space_sequencer/sequencer_quads_batch.cc index c1ffa191d14..02df45b5db6 100644 --- a/source/blender/editors/space_sequencer/sequencer_quads_batch.cc +++ b/source/blender/editors/space_sequencer/sequencer_quads_batch.cc @@ -53,10 +53,10 @@ SeqQuadsBatch::SeqQuadsBatch() batch_quads = GPU_batch_create_ex( GPU_PRIM_TRIS, vbo_quads, ibo_quads, GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX); - GPU_batch_program_set_builtin(batch_quads, GPU_SHADER_3D_FLAT_COLOR); + GPU_batch_program_set_builtin(batch_quads, GPU_SHADER_3D_SMOOTH_COLOR); batch_lines = GPU_batch_create_ex(GPU_PRIM_LINES, vbo_lines, nullptr, GPU_BATCH_OWNS_VBO); - GPU_batch_program_set_builtin(batch_lines, GPU_SHADER_3D_FLAT_COLOR); + GPU_batch_program_set_builtin(batch_lines, GPU_SHADER_3D_SMOOTH_COLOR); } SeqQuadsBatch::~SeqQuadsBatch() @@ -93,7 +93,10 @@ void SeqQuadsBatch::add_quad(float x1, float y3, float x4, float y4, - const uchar color[4]) + const uchar color1[4], + const uchar color2[4], + const uchar color3[4], + const uchar color4[4]) { if (quads_num >= MAX_QUADS) { draw(); @@ -103,10 +106,10 @@ void SeqQuadsBatch::add_quad(float x1, BLI_assert(verts_quads != nullptr); } - ColorVertex v0 = {blender::float2(x1, y1), color}; - ColorVertex v1 = {blender::float2(x2, y2), color}; - ColorVertex v2 = {blender::float2(x3, y3), color}; - ColorVertex v3 = {blender::float2(x4, y4), color}; + ColorVertex v0 = {blender::float2(x1, y1), color1}; + ColorVertex v1 = {blender::float2(x2, y2), color2}; + ColorVertex v2 = {blender::float2(x3, y3), color3}; + ColorVertex v3 = {blender::float2(x4, y4), color4}; *verts_quads++ = v0; *verts_quads++ = v1; diff --git a/source/blender/editors/space_sequencer/sequencer_quads_batch.hh b/source/blender/editors/space_sequencer/sequencer_quads_batch.hh index 05642467e96..ddb9378f53b 100644 --- a/source/blender/editors/space_sequencer/sequencer_quads_batch.hh +++ b/source/blender/editors/space_sequencer/sequencer_quads_batch.hh @@ -33,9 +33,9 @@ class SeqQuadsBatch { /** Add an axis-aligned quad. */ void add_quad(float x1, float y1, float x2, float y2, const uchar color[4]) { - add_quad(x1, y1, x1, y2, x2, y1, x2, y2, color); + add_quad(x1, y1, x1, y2, x2, y1, x2, y2, color, color, color, color); } - /** Add a quad. */ + /** Add a quad with four arbitrary coordinates and one color. */ void add_quad(float x1, float y1, float x2, @@ -44,7 +44,23 @@ class SeqQuadsBatch { float y3, float x4, float y4, - const uchar color[4]); + const uchar color[4]) + { + add_quad(x1, y1, x2, y2, x3, y3, x4, y4, color, color, color, color); + } + /** Add a quad with four arbitrary coordinates and a color for each. */ + void add_quad(float x1, + float y1, + float x2, + float y2, + float x3, + float y3, + float x4, + float y4, + const uchar color1[4], + const uchar color2[4], + const uchar color3[4], + const uchar color4[4]); /** Add four lines of an axis-aligned quad edges. */ void add_wire_quad(float x1, float y1, float x2, float y2, const uchar color[4]); /** Add a line. */ diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.cc b/source/blender/editors/space_sequencer/sequencer_scopes.cc index 4f51112380b..ac9d9f70ced 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.cc +++ b/source/blender/editors/space_sequencer/sequencer_scopes.cc @@ -54,20 +54,14 @@ void SeqScopes::cleanup() histogram.data.reinitialize(0); } -/* XXX(@ideasman42): why is this function better than BLI_math version? - * only difference is it does some normalize after, need to double check on this. */ -static void rgb_to_yuv_normalized(const float rgb[3], float yuv[3]) +static blender::float2 rgb_to_uv_normalized(const float rgb[3]) { - yuv[0] = 0.299f * rgb[0] + 0.587f * rgb[1] + 0.114f * rgb[2]; - yuv[1] = 0.492f * (rgb[2] - yuv[0]); - yuv[2] = 0.877f * (rgb[0] - yuv[0]); + float3 yuv; + rgb_to_yuv(rgb[0], rgb[1], rgb[2], &yuv.x, &yuv.y, &yuv.z, BLI_YUV_ITU_BT709); - /* Normalize. */ - yuv[1] *= 255.0f / (122 * 2.0f); - yuv[1] += 0.5f; - - yuv[2] *= 255.0f / (157 * 2.0f); - yuv[2] += 0.5f; + /* Normalize: UV range is +/- 0.615 */ + float2 uv = yuv.yz() * (0.5f / 0.615f) + 0.5f; + return math::clamp(uv, 0.0f, 1.0f); } static void scope_put_pixel(const uchar *table, uchar *pos) @@ -420,60 +414,22 @@ void ScopeHistogram::calc_from_ibuf(const ImBuf *ibuf) } } -static void vectorscope_put_cross(uchar r, uchar g, uchar b, uchar *tgt, int w, int h, int size) -{ - float rgb[3], yuv[3]; - uchar *p; - - rgb[0] = float(r) / 255.0f; - rgb[1] = float(g) / 255.0f; - rgb[2] = float(b) / 255.0f; - rgb_to_yuv_normalized(rgb, yuv); - - p = tgt + 4 * (w * int(yuv[2] * (h - 3) + 1) + int(yuv[1] * (w - 3) + 1)); - - if (r == 0 && g == 0 && b == 0) { - r = 255; - } - - for (int y = -size; y <= size; y++) { - for (int x = -size; x <= size; x++) { - uchar *q = p + 4 * (y * w + x); - q[0] = r; - q[1] = g; - q[2] = b; - q[3] = 255; - } - } -} - static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf) { #ifdef DEBUG_TIME SCOPED_TIMER_AVERAGED(__func__); #endif - ImBuf *rval = IMB_allocImBuf(515, 515, 32, IB_rect); + int w = 512; + int h = 512; + ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect); + int x, y; const uchar *src = ibuf->byte_buffer.data; uchar *tgt = rval->byte_buffer.data; - float rgb[3], yuv[3]; - int w = 515; - int h = 515; - float scope_gamma = 0.2; + float rgb[3]; + uchar wtable[256]; - - for (x = 0; x < 256; x++) { - wtable[x] = uchar(pow((float(x) + 1.0f) / 256.0f, scope_gamma) * 255.0f); - } - - for (x = 0; x < 256; x++) { - vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1); - vectorscope_put_cross(255, x, 0, tgt, w, h, 1); - vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1); - vectorscope_put_cross(0, 255, x, tgt, w, h, 1); - vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1); - vectorscope_put_cross(x, 0, 255, tgt, w, h, 1); - } + init_wave_table(math::midpoint(ibuf->x, ibuf->y), wtable); for (y = 0; y < ibuf->y; y++) { for (x = 0; x < ibuf->x; x++) { @@ -483,15 +439,13 @@ static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf) rgb[0] = float(src1[0]) / 255.0f; rgb[1] = float(src1[1]) / 255.0f; rgb[2] = float(src1[2]) / 255.0f; - rgb_to_yuv_normalized(rgb, yuv); + float2 uv = rgb_to_uv_normalized(rgb); - p = tgt + 4 * (w * int(yuv[2] * (h - 3) + 1) + int(yuv[1] * (w - 3) + 1)); + p = tgt + 4 * (w * int(uv.y * (h - 1)) + int(uv.x * (w - 1))); scope_put_pixel(wtable, (uchar *)p); } } - vectorscope_put_cross(0, 0, 0, tgt, w, h, 3); - return rval; } @@ -500,13 +454,13 @@ static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf) #ifdef DEBUG_TIME SCOPED_TIMER_AVERAGED(__func__); #endif - ImBuf *rval = IMB_allocImBuf(515, 515, 32, IB_rect); + int w = 512; + int h = 512; + ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect); int x, y; const float *src = ibuf->float_buffer.data; uchar *tgt = rval->byte_buffer.data; - float rgb[3], yuv[3]; - int w = 515; - int h = 515; + float rgb[3]; float scope_gamma = 0.2; uchar wtable[256]; @@ -514,15 +468,6 @@ static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf) wtable[x] = uchar(pow((float(x) + 1.0f) / 256.0f, scope_gamma) * 255.0f); } - for (x = 0; x <= 255; x++) { - vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1); - vectorscope_put_cross(255, x, 0, tgt, w, h, 1); - vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1); - vectorscope_put_cross(0, 255, x, tgt, w, h, 1); - vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1); - vectorscope_put_cross(x, 0, 255, tgt, w, h, 1); - } - for (y = 0; y < ibuf->y; y++) { for (x = 0; x < ibuf->x; x++) { const float *src1 = src + 4 * (ibuf->x * y + x); @@ -532,15 +477,13 @@ static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf) clamp_v3(rgb, 0.0f, 1.0f); - rgb_to_yuv_normalized(rgb, yuv); + float2 uv = rgb_to_uv_normalized(rgb); - p = tgt + 4 * (w * int(yuv[2] * (h - 3) + 1) + int(yuv[1] * (w - 3) + 1)); + p = tgt + 4 * (w * int(uv.y * (h - 1)) + int(uv.x * (w - 1))); scope_put_pixel(wtable, (uchar *)p); } } - vectorscope_put_cross(0, 0, 0, tgt, w, h, 3); - return rval; } -- 2.30.2 From 8bb10cb50076a1a9e87bcab3f037e0bbbaa1b482 Mon Sep 17 00:00:00 2001 From: Aras Pranckevicius Date: Thu, 4 Jan 2024 20:52:53 +0200 Subject: [PATCH 06/11] VSE: reduce scopes code duplication, more const --- .../space_sequencer/sequencer_preview_draw.cc | 4 +- .../space_sequencer/sequencer_scopes.cc | 419 +++++++----------- .../space_sequencer/sequencer_scopes.hh | 8 +- 3 files changed, 165 insertions(+), 266 deletions(-) diff --git a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc index 574388b6b21..44812659319 100644 --- a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc +++ b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc @@ -160,7 +160,9 @@ ImBuf *sequencer_ibuf_get(Main *bmain, return ibuf; } -static ImBuf *sequencer_make_scope(Scene *scene, ImBuf *ibuf, ImBuf *(*make_scope_fn)(ImBuf *ibuf)) +static ImBuf *sequencer_make_scope(Scene *scene, + ImBuf *ibuf, + ImBuf *(*make_scope_fn)(const ImBuf *ibuf)) { ImBuf *display_ibuf = IMB_dupImBuf(ibuf); ImBuf *scope; diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.cc b/source/blender/editors/space_sequencer/sequencer_scopes.cc index ac9d9f70ced..72f904e3f8e 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.cc +++ b/source/blender/editors/space_sequencer/sequencer_scopes.cc @@ -101,16 +101,14 @@ static void init_wave_table(int height, uchar wtable[256]) } } -static ImBuf *make_waveform_view_from_ibuf_byte(ImBuf *ibuf) +ImBuf *make_waveform_view_from_ibuf(const ImBuf *ibuf) { #ifdef DEBUG_TIME - SCOPED_TIMER_AVERAGED(__func__); + SCOPED_TIMER(__func__); #endif - using namespace blender; - int w = ibuf->x; - int h = 256; + const int w = ibuf->x; + const int h = 256; ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect); - const uchar *src = ibuf->byte_buffer.data; uchar *tgt = rval->byte_buffer.data; uchar wtable[256]; @@ -123,132 +121,37 @@ static ImBuf *make_waveform_view_from_ibuf_byte(ImBuf *ibuf) int muls[3] = {int(coeffs[0] * 65535), int(coeffs[1] * 65535), int(coeffs[2] * 65535)}; /* Parallel over x, since each column is easily independent from others. */ - threading::parallel_for(IndexRange(ibuf->x), 16, [&](IndexRange x_range) { - for (int y = 0; y < ibuf->y; y++) { - - for (const int x : x_range) { - const uchar *rgb = src + 4 * (ibuf->x * y + x); - /* +1 is "Sree's solution" from http://stereopsis.com/doubleblend.html */ - int rgb0 = rgb[0] + 1; - int rgb1 = rgb[1] + 1; - int rgb2 = rgb[2] + 1; - int luma = (rgb0 * muls[0] + rgb1 * muls[1] + rgb2 * muls[2]) >> 16; - int luma_y = clamp_i(luma, 0, 255); - uchar *p = tgt + 4 * (w * luma_y + x); - scope_put_pixel(wtable, p); - } - } - }); - - return rval; -} - -static ImBuf *make_waveform_view_from_ibuf_float(ImBuf *ibuf) -{ -#ifdef DEBUG_TIME - SCOPED_TIMER_AVERAGED(__func__); -#endif - using namespace blender; - int w = ibuf->x; - int h = 256; - ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect); - const float *src = ibuf->float_buffer.data; - uchar *tgt = rval->byte_buffer.data; - - uchar wtable[256]; - init_wave_table(ibuf->y, wtable); - - /* Parallel over x, since each column is easily independent from others. */ - threading::parallel_for(IndexRange(ibuf->x), 16, [&](IndexRange x_range) { - for (int y = 0; y < ibuf->y; y++) { - - for (const int x : x_range) { - const float *rgb = src + 4 * (ibuf->x * y + x); - float v = IMB_colormanagement_get_luminance(rgb); - uchar *p = tgt; - - int iv = clamp_i(int(v * h), 0, h - 1); - - p += 4 * (w * iv + x); - scope_put_pixel(wtable, p); - } - } - }); - - return rval; -} - -ImBuf *make_waveform_view_from_ibuf(ImBuf *ibuf) -{ - if (ibuf->float_buffer.data) { - return make_waveform_view_from_ibuf_float(ibuf); - } - return make_waveform_view_from_ibuf_byte(ibuf); -} - -static ImBuf *make_sep_waveform_view_from_ibuf_byte(ImBuf *ibuf) -{ -#ifdef DEBUG_TIME - SCOPED_TIMER_AVERAGED(__func__); -#endif - using namespace blender; - int w = ibuf->x; - int h = 256; - ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect); - const uchar *src = ibuf->byte_buffer.data; - uchar *tgt = rval->byte_buffer.data; - int sw = ibuf->x / 3; - - uchar wtable[256]; - init_wave_table(ibuf->y, wtable); - - /* Parallel over x, since each column is easily independent from others. */ - threading::parallel_for(IndexRange(ibuf->x), 16, [&](IndexRange x_range) { - for (int y = 0; y < ibuf->y; y++) { - for (const int x : x_range) { - int c; - const uchar *rgb = src + 4 * (ibuf->x * y + x); - for (c = 0; c < 3; c++) { + threading::parallel_for(IndexRange(ibuf->x), 32, [&](IndexRange x_range) { + if (ibuf->float_buffer.data) { + /* Float image. */ + const float *src = ibuf->float_buffer.data; + for (int y = 0; y < ibuf->y; y++) { + for (const int x : x_range) { + const float *rgb = src + 4 * (ibuf->x * y + x); + float v = IMB_colormanagement_get_luminance(rgb); uchar *p = tgt; - p += 4 * (w * rgb[c] + c * sw + x / 3); - scope_put_pixel_single(wtable, p, c); - } - } - } - }); - return rval; -} - -static ImBuf *make_sep_waveform_view_from_ibuf_float(ImBuf *ibuf) -{ -#ifdef DEBUG_TIME - SCOPED_TIMER_AVERAGED(__func__); -#endif - using namespace blender; - int w = ibuf->x; - int h = 256; - ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect); - const float *src = ibuf->float_buffer.data; - uchar *tgt = rval->byte_buffer.data; - int sw = ibuf->x / 3; - - uchar wtable[256]; - init_wave_table(ibuf->y, wtable); - - /* Parallel over x, since each column is easily independent from others. */ - threading::parallel_for(IndexRange(ibuf->x), 16, [&](IndexRange x_range) { - for (int y = 0; y < ibuf->y; y++) { - for (const int x : x_range) { - int c; - const float *rgb = src + 4 * (ibuf->x * y + x); - for (c = 0; c < 3; c++) { - uchar *p = tgt; - float v = rgb[c]; int iv = clamp_i(int(v * h), 0, h - 1); - p += 4 * (w * iv + c * sw + x / 3); - scope_put_pixel_single(wtable, p, c); + p += 4 * (w * iv + x); + scope_put_pixel(wtable, p); + } + } + } + else { + /* Byte image. */ + const uchar *src = ibuf->byte_buffer.data; + for (int y = 0; y < ibuf->y; y++) { + for (const int x : x_range) { + const uchar *rgb = src + 4 * (ibuf->x * y + x); + /* +1 is "Sree's solution" from http://stereopsis.com/doubleblend.html */ + int rgb0 = rgb[0] + 1; + int rgb1 = rgb[1] + 1; + int rgb2 = rgb[2] + 1; + int luma = (rgb0 * muls[0] + rgb1 * muls[1] + rgb2 * muls[2]) >> 16; + int luma_y = clamp_i(luma, 0, 255); + uchar *p = tgt + 4 * (w * luma_y + x); + scope_put_pixel(wtable, p); } } } @@ -257,92 +160,113 @@ static ImBuf *make_sep_waveform_view_from_ibuf_float(ImBuf *ibuf) return rval; } -ImBuf *make_sep_waveform_view_from_ibuf(ImBuf *ibuf) -{ - if (ibuf->float_buffer.data) { - return make_sep_waveform_view_from_ibuf_float(ibuf); - } - return make_sep_waveform_view_from_ibuf_byte(ibuf); -} - -static void draw_zebra_byte(const ImBuf *src, ImBuf *ibuf, float perc) +ImBuf *make_sep_waveform_view_from_ibuf(const ImBuf *ibuf) { #ifdef DEBUG_TIME - SCOPED_TIMER_AVERAGED(__func__); + SCOPED_TIMER(__func__); #endif - using namespace blender; - uint limit = 255.0f * perc / 100.0f; + int w = ibuf->x; + int h = 256; + ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect); + uchar *tgt = rval->byte_buffer.data; + int sw = ibuf->x / 3; - threading::parallel_for(IndexRange(ibuf->y), 16, [&](IndexRange y_range) { - const uchar *p = src->byte_buffer.data + y_range.first() * ibuf->x * 4; - uchar *o = ibuf->byte_buffer.data + y_range.first() * ibuf->x * 4; - for (const int y : y_range) { - for (int x = 0; x < ibuf->x; x++) { - uchar r = *p++; - uchar g = *p++; - uchar b = *p++; - uchar a = *p++; + uchar wtable[256]; + init_wave_table(ibuf->y, wtable); - if (r >= limit || g >= limit || b >= limit) { - if (((x + y) & 0x08) != 0) { - r = 255 - r; - g = 255 - g; - b = 255 - b; + /* Parallel over x, since each column is easily independent from others. */ + threading::parallel_for(IndexRange(ibuf->x), 32, [&](IndexRange x_range) { + if (ibuf->float_buffer.data) { + /* Float image. */ + const float *src = ibuf->float_buffer.data; + for (int y = 0; y < ibuf->y; y++) { + for (const int x : x_range) { + const float *rgb = src + 4 * (ibuf->x * y + x); + for (int c = 0; c < 3; c++) { + uchar *p = tgt; + float v = rgb[c]; + int iv = clamp_i(int(v * h), 0, h - 1); + + p += 4 * (w * iv + c * sw + x / 3); + scope_put_pixel_single(wtable, p, c); + } + } + } + } + else { + /* Byte image. */ + const uchar *src = ibuf->byte_buffer.data; + for (int y = 0; y < ibuf->y; y++) { + for (const int x : x_range) { + const uchar *rgb = src + 4 * (ibuf->x * y + x); + for (int c = 0; c < 3; c++) { + uchar *p = tgt; + p += 4 * (w * rgb[c] + c * sw + x / 3); + scope_put_pixel_single(wtable, p, c); } } - *o++ = r; - *o++ = g; - *o++ = b; - *o++ = a; } } }); + + return rval; } -static void draw_zebra_float(ImBuf *src, ImBuf *ibuf, float perc) +ImBuf *make_zebra_view_from_ibuf(const ImBuf *ibuf, float perc) { #ifdef DEBUG_TIME - SCOPED_TIMER_AVERAGED(__func__); + SCOPED_TIMER(__func__); #endif - using namespace blender; - - float limit = perc / 100.0f; + ImBuf *res = IMB_allocImBuf(ibuf->x, ibuf->y, 32, IB_rect); threading::parallel_for(IndexRange(ibuf->y), 16, [&](IndexRange y_range) { - const float *p = src->float_buffer.data + y_range.first() * ibuf->x * 4; - uchar *o = ibuf->byte_buffer.data + y_range.first() * ibuf->x * 4; - for (const int y : y_range) { - for (int x = 0; x < ibuf->x; x++) { - float pix[4]; - pix[0] = *p++; - pix[1] = *p++; - pix[2] = *p++; - pix[3] = *p++; - if (pix[0] >= limit || pix[1] >= limit || pix[2] >= limit) { - if (((x + y) & 0x08) != 0) { - pix[0] = -pix[0]; - pix[1] = -pix[1]; - pix[2] = -pix[2]; + if (ibuf->float_buffer.data) { + /* Float image. */ + const float limit = perc / 100.0f; + const float *p = ibuf->float_buffer.data + y_range.first() * ibuf->x * 4; + uchar *o = res->byte_buffer.data + y_range.first() * ibuf->x * 4; + for (const int y : y_range) { + for (int x = 0; x < ibuf->x; x++) { + float pix[4]; + memcpy(pix, p, sizeof(pix)); + if (pix[0] >= limit || pix[1] >= limit || pix[2] >= limit) { + if (((x + y) & 0x08) != 0) { + pix[0] = -pix[0]; + pix[1] = -pix[1]; + pix[2] = -pix[2]; + } } + rgba_float_to_uchar(o, pix); + p += 4; + o += 4; + } + } + } + else { + /* Byte image. */ + const uint limit = 255.0f * perc / 100.0f; + const uchar *p = ibuf->byte_buffer.data + y_range.first() * ibuf->x * 4; + uchar *o = res->byte_buffer.data + y_range.first() * ibuf->x * 4; + for (const int y : y_range) { + for (int x = 0; x < ibuf->x; x++) { + uchar pix[4]; + memcpy(pix, p, sizeof(pix)); + + if (pix[0] >= limit || pix[1] >= limit || pix[2] >= limit) { + if (((x + y) & 0x08) != 0) { + pix[0] = 255 - pix[0]; + pix[1] = 255 - pix[1]; + pix[2] = 255 - pix[2]; + } + } + memcpy(o, pix, sizeof(pix)); + p += 4; + o += 4; } - rgba_float_to_uchar(o, pix); - o += 4; } } }); -} - -ImBuf *make_zebra_view_from_ibuf(ImBuf *ibuf, float perc) -{ - ImBuf *new_ibuf = IMB_allocImBuf(ibuf->x, ibuf->y, 32, IB_rect); - - if (ibuf->float_buffer.data) { - draw_zebra_float(ibuf, new_ibuf, perc); - } - else { - draw_zebra_byte(ibuf, new_ibuf, perc); - } - return new_ibuf; + return res; } static int get_bin_float(float f) @@ -359,7 +283,7 @@ static int get_bin_float(float f) void ScopeHistogram::calc_from_ibuf(const ImBuf *ibuf) { #ifdef DEBUG_TIME - SCOPED_TIMER_AVERAGED(__func__); + SCOPED_TIMER(__func__); #endif const bool is_float = ibuf->float_buffer.data != nullptr; @@ -414,85 +338,58 @@ void ScopeHistogram::calc_from_ibuf(const ImBuf *ibuf) } } -static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf) +ImBuf *make_vectorscope_view_from_ibuf(const ImBuf *ibuf) { #ifdef DEBUG_TIME - SCOPED_TIMER_AVERAGED(__func__); + SCOPED_TIMER(__func__); #endif - int w = 512; - int h = 512; - ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect); + const int size = 512; + const float size_mul = size - 1.0f; + ImBuf *rval = IMB_allocImBuf(size, size, 32, IB_rect); - int x, y; - const uchar *src = ibuf->byte_buffer.data; - uchar *tgt = rval->byte_buffer.data; + uchar *dst = rval->byte_buffer.data; float rgb[3]; uchar wtable[256]; init_wave_table(math::midpoint(ibuf->x, ibuf->y), wtable); - for (y = 0; y < ibuf->y; y++) { - for (x = 0; x < ibuf->x; x++) { - const uchar *src1 = src + 4 * (ibuf->x * y + x); - uchar *p; - - rgb[0] = float(src1[0]) / 255.0f; - rgb[1] = float(src1[1]) / 255.0f; - rgb[2] = float(src1[2]) / 255.0f; - float2 uv = rgb_to_uv_normalized(rgb); - - p = tgt + 4 * (w * int(uv.y * (h - 1)) + int(uv.x * (w - 1))); - scope_put_pixel(wtable, (uchar *)p); - } - } - - return rval; -} - -static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf) -{ -#ifdef DEBUG_TIME - SCOPED_TIMER_AVERAGED(__func__); -#endif - int w = 512; - int h = 512; - ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect); - int x, y; - const float *src = ibuf->float_buffer.data; - uchar *tgt = rval->byte_buffer.data; - float rgb[3]; - float scope_gamma = 0.2; - uchar wtable[256]; - - for (x = 0; x < 256; x++) { - wtable[x] = uchar(pow((float(x) + 1.0f) / 256.0f, scope_gamma) * 255.0f); - } - - for (y = 0; y < ibuf->y; y++) { - for (x = 0; x < ibuf->x; x++) { - const float *src1 = src + 4 * (ibuf->x * y + x); - const uchar *p; - - memcpy(rgb, src1, sizeof(float[3])); - - clamp_v3(rgb, 0.0f, 1.0f); - - float2 uv = rgb_to_uv_normalized(rgb); - - p = tgt + 4 * (w * int(uv.y * (h - 1)) + int(uv.x * (w - 1))); - scope_put_pixel(wtable, (uchar *)p); - } - } - - return rval; -} - -ImBuf *make_vectorscope_view_from_ibuf(ImBuf *ibuf) -{ if (ibuf->float_buffer.data) { - return make_vectorscope_view_from_ibuf_float(ibuf); + /* Float image. */ + const float *src = ibuf->float_buffer.data; + for (int y = 0; y < ibuf->y; y++) { + for (int x = 0; x < ibuf->x; x++) { + memcpy(rgb, src, sizeof(float[3])); + clamp_v3(rgb, 0.0f, 1.0f); + + float2 uv = rgb_to_uv_normalized(rgb) * size_mul; + + uchar *p = dst + 4 * (size * int(uv.y) + int(uv.x)); + scope_put_pixel(wtable, p); + + src += 4; + } + } } - return make_vectorscope_view_from_ibuf_byte(ibuf); + else { + /* Byte image. */ + const uchar *src = ibuf->byte_buffer.data; + for (int y = 0; y < ibuf->y; y++) { + for (int x = 0; x < ibuf->x; x++) { + rgb[0] = float(src[0]) * (1.0f / 255.0f); + rgb[1] = float(src[1]) * (1.0f / 255.0f); + rgb[2] = float(src[2]) * (1.0f / 255.0f); + + float2 uv = rgb_to_uv_normalized(rgb) * size_mul; + + uchar *p = dst + 4 * (size * int(uv.y) + int(uv.x)); + scope_put_pixel(wtable, p); + + src += 4; + } + } + } + + return rval; } } // namespace blender::ed::seq diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.hh b/source/blender/editors/space_sequencer/sequencer_scopes.hh index 293d79551b6..9fa67047612 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.hh +++ b/source/blender/editors/space_sequencer/sequencer_scopes.hh @@ -39,9 +39,9 @@ struct SeqScopes { ScopeHistogram histogram; }; -ImBuf *make_waveform_view_from_ibuf(ImBuf *ibuf); -ImBuf *make_sep_waveform_view_from_ibuf(ImBuf *ibuf); -ImBuf *make_vectorscope_view_from_ibuf(ImBuf *ibuf); -ImBuf *make_zebra_view_from_ibuf(ImBuf *ibuf, float perc); +ImBuf *make_waveform_view_from_ibuf(const ImBuf *ibuf); +ImBuf *make_sep_waveform_view_from_ibuf(const ImBuf *ibuf); +ImBuf *make_vectorscope_view_from_ibuf(const ImBuf *ibuf); +ImBuf *make_zebra_view_from_ibuf(const ImBuf *ibuf, float perc); } // namespace blender::ed::seq -- 2.30.2 From 099033fc57f36f265ebf754353f603c7221cbb52 Mon Sep 17 00:00:00 2001 From: Aras Pranckevicius Date: Thu, 4 Jan 2024 20:57:47 +0200 Subject: [PATCH 07/11] VSE: overexposed/zebra overlay consistency between byte and float images Byte is showing inverted (white-color) overlay, whereas float was showing overlay as black stripes. Goes back to 16 years ago when VSE code was added. Looks like an accident, made both show inverted colors. --- source/blender/editors/space_sequencer/sequencer_scopes.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.cc b/source/blender/editors/space_sequencer/sequencer_scopes.cc index 72f904e3f8e..1e5f2d68967 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.cc +++ b/source/blender/editors/space_sequencer/sequencer_scopes.cc @@ -231,9 +231,9 @@ ImBuf *make_zebra_view_from_ibuf(const ImBuf *ibuf, float perc) memcpy(pix, p, sizeof(pix)); if (pix[0] >= limit || pix[1] >= limit || pix[2] >= limit) { if (((x + y) & 0x08) != 0) { - pix[0] = -pix[0]; - pix[1] = -pix[1]; - pix[2] = -pix[2]; + pix[0] = 1.0f - pix[0]; + pix[1] = 1.0f - pix[1]; + pix[2] = 1.0f - pix[2]; } } rgba_float_to_uchar(o, pix); -- 2.30.2 From d52353c55093983ab3d75b47f554630cb8b2def0 Mon Sep 17 00:00:00 2001 From: Aras Pranckevicius Date: Thu, 4 Jan 2024 22:05:08 +0200 Subject: [PATCH 08/11] VSE: tweak vectorscope perf and look Non-inlined call to rgb_to_yuv was costing a lot of perf, do the calculations inline with a note. Also tweak the look to scale U,V non-uniformly, similar to previous scope behavior. Uses the horizontal texture resolution better. --- .../space_sequencer/sequencer_preview_draw.cc | 39 ++++++++++--------- .../space_sequencer/sequencer_quads_batch.cc | 7 ++-- .../space_sequencer/sequencer_quads_batch.hh | 10 ++++- .../space_sequencer/sequencer_scopes.cc | 16 +++++--- 4 files changed, 44 insertions(+), 28 deletions(-) diff --git a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc index 44812659319..af979456f45 100644 --- a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc +++ b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc @@ -592,16 +592,17 @@ static void draw_vectorscope_graticule(SeqQuadsBatch &quads, const rctf &area) const float h = BLI_rctf_size_y(&area); const float centerx = BLI_rctf_cent_x(&area); const float centery = BLI_rctf_cent_y(&area); - const float radius = ((w < h) ? w : h) * 0.5f * (0.5f / 0.615f); + const float rad_base = ((w < h) ? w : h) * 0.5f; + /* vectorscope image is scaled over YUV range, +/- (0.436, 0.615) */ + const float rad_x = rad_base * (0.5f / 0.436f); + const float rad_y = rad_base * (0.5f / 0.615f); /* center cross */ uchar col_grid[4] = {128, 128, 128, 96}; - quads.add_line(centerx - radius * 0.1f, centery, centerx + radius * 0.1f, centery, col_grid); - quads.add_line(centerx, centery - radius * 0.1f, centerx, centery + radius * 0.1f, col_grid); + quads.add_line(centerx - rad_base * 0.1f, centery, centerx + rad_base * 0.1f, centery, col_grid); + quads.add_line(centerx, centery - rad_base * 0.1f, centerx, centery + rad_base * 0.1f, col_grid); /* fully saturated vs "safe" (0.75) colored areas */ - quads.draw(); - GPU_blend(GPU_BLEND_ADDITIVE); const float3 primaries[6] = { {1, 0, 0}, {1, 1, 0}, @@ -611,31 +612,33 @@ static void draw_vectorscope_graticule(SeqQuadsBatch &quads, const rctf &area) {1, 0, 1}, }; float2 center{centerx, centery}; + float2 rad_scale{rad_x * 2, rad_y * 2}; for (int i = 0; i < 6; i++) { float3 prim0 = primaries[i]; float3 prim1 = primaries[(i + 1) % 6]; float3 safe0 = prim0 * 0.75f; float3 safe1 = prim1 * 0.75f; - float2 uv0 = center + rgb_to_uv(prim0) * (radius * 2); - float2 uv1 = center + rgb_to_uv(prim1) * (radius * 2); - float2 uv2 = center + rgb_to_uv(safe0) * (radius * 2); - float2 uv3 = center + rgb_to_uv(safe1) * (radius * 2); - uchar col0[4] = {uchar(prim0.x * 255), uchar(prim0.y * 255), uchar(prim0.z * 255), 128}; - uchar col1[4] = {uchar(prim1.x * 255), uchar(prim1.y * 255), uchar(prim1.z * 255), 128}; - uchar col2[4] = {uchar(safe0.x * 255), uchar(safe0.y * 255), uchar(safe0.z * 255), 128}; - uchar col3[4] = {uchar(safe1.x * 255), uchar(safe1.y * 255), uchar(safe1.z * 255), 128}; + float2 uv0 = center + rgb_to_uv(prim0) * rad_scale; + float2 uv1 = center + rgb_to_uv(prim1) * rad_scale; + float2 uv2 = center + rgb_to_uv(safe0) * rad_scale; + float2 uv3 = center + rgb_to_uv(safe1) * rad_scale; + uchar col0[4] = {uchar(prim0.x * 255), uchar(prim0.y * 255), uchar(prim0.z * 255), 64}; + uchar col1[4] = {uchar(prim1.x * 255), uchar(prim1.y * 255), uchar(prim1.z * 255), 64}; + uchar col2[4] = {uchar(safe0.x * 255), uchar(safe0.y * 255), uchar(safe0.z * 255), 64}; + uchar col3[4] = {uchar(safe1.x * 255), uchar(safe1.y * 255), uchar(safe1.z * 255), 64}; quads.add_quad(uv0.x, uv0.y, uv1.x, uv1.y, uv2.x, uv2.y, uv3.x, uv3.y, col0, col1, col2, col3); + col0[3] = col1[3] = col2[3] = col3[3] = 192; + quads.add_line(uv0.x, uv0.y, uv1.x, uv1.y, col0, col1); + quads.add_line(uv2.x, uv2.y, uv3.x, uv3.y, col2, col3); } - quads.draw(); - GPU_blend(GPU_BLEND_ALPHA); /* skin tone line */ uchar col_tone[4] = {255, 102, 0, 128}; - const float tone_line_len = radius * 0.895f; /* makes it end at outer edge of saturation ring */ + const float tone_line_len = 0.895f; /* makes it end at outer edge of saturation ring */ quads.add_line(centerx, centery, - centerx + cosf(skin_rad) * tone_line_len, - centery + sinf(skin_rad) * tone_line_len, + centerx + cosf(skin_rad) * rad_x * tone_line_len, + centery + sinf(skin_rad) * rad_y * tone_line_len, col_tone); } diff --git a/source/blender/editors/space_sequencer/sequencer_quads_batch.cc b/source/blender/editors/space_sequencer/sequencer_quads_batch.cc index 02df45b5db6..eae6452cd48 100644 --- a/source/blender/editors/space_sequencer/sequencer_quads_batch.cc +++ b/source/blender/editors/space_sequencer/sequencer_quads_batch.cc @@ -150,7 +150,8 @@ void SeqQuadsBatch::add_wire_quad(float x1, float y1, float x2, float y2, const lines_num += 4; } -void SeqQuadsBatch::add_line(float x1, float y1, float x2, float y2, const uchar color[4]) +void SeqQuadsBatch::add_line( + float x1, float y1, float x2, float y2, const uchar color1[4], const uchar color2[4]) { if (lines_num + 1 > MAX_LINES) { draw(); @@ -160,8 +161,8 @@ void SeqQuadsBatch::add_line(float x1, float y1, float x2, float y2, const uchar BLI_assert(verts_lines != nullptr); } - ColorVertex v0 = {blender::float2(x1, y1), color}; - ColorVertex v1 = {blender::float2(x2, y2), color}; + ColorVertex v0 = {blender::float2(x1, y1), color1}; + ColorVertex v1 = {blender::float2(x2, y2), color2}; *verts_lines++ = v0; *verts_lines++ = v1; diff --git a/source/blender/editors/space_sequencer/sequencer_quads_batch.hh b/source/blender/editors/space_sequencer/sequencer_quads_batch.hh index ddb9378f53b..b4bf85b521e 100644 --- a/source/blender/editors/space_sequencer/sequencer_quads_batch.hh +++ b/source/blender/editors/space_sequencer/sequencer_quads_batch.hh @@ -63,8 +63,14 @@ class SeqQuadsBatch { const uchar color4[4]); /** Add four lines of an axis-aligned quad edges. */ void add_wire_quad(float x1, float y1, float x2, float y2, const uchar color[4]); - /** Add a line. */ - void add_line(float x1, float y1, float x2, float y2, const uchar color[4]); + /** Add a line with single color. */ + void add_line(float x1, float y1, float x2, float y2, const uchar color[4]) + { + add_line(x1, y1, x2, y2, color, color); + } + /** Add a line with two endpoint colors. */ + void add_line( + float x1, float y1, float x2, float y2, const uchar color1[4], const uchar color2[4]); private: static constexpr int MAX_QUADS = 1024; diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.cc b/source/blender/editors/space_sequencer/sequencer_scopes.cc index 1e5f2d68967..7853ee27572 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.cc +++ b/source/blender/editors/space_sequencer/sequencer_scopes.cc @@ -56,12 +56,18 @@ void SeqScopes::cleanup() static blender::float2 rgb_to_uv_normalized(const float rgb[3]) { - float3 yuv; - rgb_to_yuv(rgb[0], rgb[1], rgb[2], &yuv.x, &yuv.y, &yuv.z, BLI_YUV_ITU_BT709); + /* Exact same math as rgb_to_yuv BT709 case. Duplicated here + * since this function is called a lot, and non-inline function + * call plus colorspace switch in there overhead does add up. */ + float r = rgb[0], g = rgb[1], b = rgb[2]; + /* We don't need y. */ + float u = -0.09991f * r - 0.33609f * g + 0.436f * b; + float v = 0.615f * r - 0.55861f * g - 0.05639f * b; - /* Normalize: UV range is +/- 0.615 */ - float2 uv = yuv.yz() * (0.5f / 0.615f) + 0.5f; - return math::clamp(uv, 0.0f, 1.0f); + /* Normalize: (U, V) range is +/- (0.436, 0.615) */ + u = clamp_f(u * (0.5f / 0.436f) + 0.5f, 0.0f, 1.0f); + v = clamp_f(v * (0.5f / 0.615f) + 0.5f, 0.0f, 1.0f); + return float2(u, v); } static void scope_put_pixel(const uchar *table, uchar *pos) -- 2.30.2 From 05927be0703fb94a97d027a2ce60675b6a62dd35 Mon Sep 17 00:00:00 2001 From: Aras Pranckevicius Date: Thu, 4 Jan 2024 22:17:29 +0200 Subject: [PATCH 09/11] VSE: fix new histogram code not being multi-threaded New code uses C++ threading::parallel_reduce, but that requires WITH_TBB to be set on cmake side. --- source/blender/editors/space_sequencer/CMakeLists.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt index cb9c834869c..2fe7439d926 100644 --- a/source/blender/editors/space_sequencer/CMakeLists.txt +++ b/source/blender/editors/space_sequencer/CMakeLists.txt @@ -74,6 +74,16 @@ if(WITH_AUDASPACE) add_definitions(-DWITH_AUDASPACE) endif() +if(WITH_TBB) + add_definitions(-DWITH_TBB) + list(APPEND INC_SYS + ${TBB_INCLUDE_DIRS} + ) + list(APPEND LIB + ${TBB_LIBRARIES} + ) +endif() + blender_add_lib(bf_editor_space_sequencer "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") -- 2.30.2 From 9226321a99d5a882d094e030b3eaf52ca88fd4dc Mon Sep 17 00:00:00 2001 From: Aras Pranckevicius Date: Thu, 4 Jan 2024 23:22:52 +0200 Subject: [PATCH 10/11] VSE: add text labels to histogram and wavefrom scope grids --- .../space_sequencer/sequencer_preview_draw.cc | 70 ++++++++++++++----- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc index af979456f45..4bdd1b7d4da 100644 --- a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc +++ b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc @@ -9,6 +9,8 @@ #include #include +#include "BLF_api.h" + #include "BLI_blenlib.h" #include "BLI_math_rotation.h" #include "BLI_utildefines.h" @@ -517,7 +519,8 @@ static void sequencer_draw_display_buffer(const bContext *C, } } -static void draw_histogram(const blender::ed::seq::ScopeHistogram &hist, +static void draw_histogram(ARegion *region, + const blender::ed::seq::ScopeHistogram &hist, SeqQuadsBatch &quads, const rctf &area) { @@ -529,17 +532,36 @@ static void draw_histogram(const blender::ed::seq::ScopeHistogram &hist, uchar col_bg[4] = {0, 0, 0, 255}; quads.add_quad(area.xmin, area.ymin, area.xmax, area.ymax, col_bg); - /* Grid lines. */ + /* Grid lines and labels. */ uchar col_grid[4] = {128, 128, 128, 128}; float grid_x_0 = area.xmin; float grid_x_1 = area.xmax; + /* Float histograms show -0.25 .. 1.25 area horizontally. */ if (hist.data.size() > 256) { grid_x_0 = area.xmin + (area.xmax - area.xmin) * (0.25f / 1.5f); grid_x_1 = area.xmin + (area.xmax - area.xmin) * (1.25f / 1.5f); } + + View2D *v2d = ®ion->v2d; + const float text_scale_x = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); + const float text_scale_y = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask); + for (int line = 0; line <= 4; line++) { - float x = grid_x_0 + (grid_x_1 - grid_x_0) * line / 4; + float val = float(line) / 4; + float x = grid_x_0 + (grid_x_1 - grid_x_0) * val; quads.add_line(x, area.ymin, x, area.ymax, col_grid); + + /* Label. */ + char buf[10]; + snprintf(buf, sizeof(buf), "%.2f", val); + size_t buf_len = strlen(buf); + + float text_width, text_height; + BLF_width_and_height(BLF_default(), buf, buf_len, &text_width, &text_height); + text_width *= text_scale_x; + text_height *= text_scale_y; + UI_view2d_text_cache_add( + v2d, x - text_width / 2, area.ymax - text_height * 1.3f, buf, buf_len, col_grid); } /* Border. */ @@ -572,6 +594,8 @@ static void draw_histogram(const blender::ed::seq::ScopeHistogram &hist, } quads.draw(); GPU_blend(GPU_BLEND_ALPHA); + + UI_view2d_text_cache_draw(region); } static blender::float2 rgb_to_uv(const blender::float3 &rgb) @@ -581,6 +605,29 @@ static blender::float2 rgb_to_uv(const blender::float3 &rgb) return blender::float2(u, v); } +static void draw_waveform_graticule(ARegion *region, SeqQuadsBatch &quads, const rctf &area) +{ + /* Horizontal lines at 10%, 70%, 90%. */ + const float lines[3] = {0.1f, 0.7f, 0.9f}; + uchar col_grid[4] = {160, 64, 64, 128}; + const float x0 = area.xmin; + const float x1 = area.xmax; + + for (int i = 0; i < 3; i++) { + const float y = area.ymin + (area.ymax - area.ymin) * lines[i]; + char buf[10]; + snprintf(buf, sizeof(buf), "%.1f", lines[i]); + quads.add_line(x0, y, x1, y, col_grid); + UI_view2d_text_cache_add(®ion->v2d, x0 + 8, y + 8, buf, strlen(buf), col_grid); + } + /* Border. */ + uchar col_border[4] = {64, 64, 64, 128}; + quads.add_wire_quad(x0, area.ymin, x1, area.ymax, col_border); + + quads.draw(); + UI_view2d_text_cache_draw(region); +} + static void draw_vectorscope_graticule(SeqQuadsBatch &quads, const rctf &area) { using namespace blender; @@ -741,22 +788,11 @@ static void sequencer_draw_scopes(Scene *scene, ARegion *region, SpaceSeq *sseq, } if (sseq->mainb == SEQ_DRAW_IMG_HISTOGRAM) { - draw_histogram(scopes->histogram, quads, preview); + draw_histogram(region, scopes->histogram, quads, preview); } if (sseq->mainb == SEQ_DRAW_IMG_WAVEFORM) { - /* Horizontal lines at 10%, 70%, 90%. */ - uchar col_grid[4] = {160, 64, 64, 128}; - const float x0 = preview.xmin; - const float x1 = preview.xmax; - const float y10 = preview.ymin + (preview.ymax - preview.ymin) * 0.10f; - const float y70 = preview.ymin + (preview.ymax - preview.ymin) * 0.70f; - const float y90 = preview.ymin + (preview.ymax - preview.ymin) * 0.90f; - quads.add_line(x0, y10, x1, y10, col_grid); - quads.add_line(x0, y70, x1, y70, col_grid); - quads.add_line(x0, y90, x1, y90, col_grid); - /* Border. */ - uchar col_border[4] = {64, 64, 64, 128}; - quads.add_wire_quad(x0, preview.ymin, x1, preview.ymax, col_border); + use_blend = true; + draw_waveform_graticule(region, quads, preview); } if (sseq->mainb == SEQ_DRAW_IMG_VECTORSCOPE) { use_blend = true; -- 2.30.2 From 294c66ccad96fa18aab6c0fd594e5893422a12f0 Mon Sep 17 00:00:00 2001 From: Aras Pranckevicius Date: Fri, 5 Jan 2024 21:25:35 +0200 Subject: [PATCH 11/11] VSE: code review --- .../space_sequencer/sequencer_intern.hh | 10 +++-- .../space_sequencer/sequencer_preview_draw.cc | 38 +++++++++---------- .../space_sequencer/sequencer_scopes.cc | 14 +++---- .../space_sequencer/sequencer_scopes.hh | 26 ++++++++----- .../space_sequencer/space_sequencer.cc | 2 +- source/blender/makesdna/DNA_space_types.h | 9 +++-- 6 files changed, 53 insertions(+), 46 deletions(-) diff --git a/source/blender/editors/space_sequencer/sequencer_intern.hh b/source/blender/editors/space_sequencer/sequencer_intern.hh index d4384dde56a..cb8d9c71069 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.hh +++ b/source/blender/editors/space_sequencer/sequencer_intern.hh @@ -8,6 +8,7 @@ #pragma once +#include "BLI_utility_mixins.hh" #include "BLI_vector.hh" #include "BLI_vector_set.hh" #include "DNA_sequence_types.h" @@ -42,7 +43,9 @@ struct ListBase; #define DEFAULT_IMG_STRIP_LENGTH 25 /* XXX arbitrary but ok for now. */ #define OVERLAP_ALPHA 180 -struct SpaceSeq_Runtime { +namespace blender::ed::seq { + +struct SpaceSeq_Runtime : public NonCopyable { /** Required for Thumbnail job start condition. */ rctf last_thumbnail_area = {0, 0, 0, 0}; /** Stores lists of most recently displayed thumbnails. */ @@ -53,12 +56,11 @@ struct SpaceSeq_Runtime { blender::ed::seq::SeqScopes scopes; SpaceSeq_Runtime() = default; - SpaceSeq_Runtime(const SpaceSeq_Runtime &) = delete; - void operator=(const SpaceSeq_Runtime &) = delete; - ~SpaceSeq_Runtime(); }; +} // namespace blender::ed::seq + struct SeqChannelDrawContext { const bContext *C; ScrArea *area; diff --git a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc index 4bdd1b7d4da..0a963a4d83c 100644 --- a/source/blender/editors/space_sequencer/sequencer_preview_draw.cc +++ b/source/blender/editors/space_sequencer/sequencer_preview_draw.cc @@ -524,6 +524,7 @@ static void draw_histogram(ARegion *region, SeqQuadsBatch &quads, const rctf &area) { + using namespace blender::ed::seq; if (hist.data.is_empty()) { return; } @@ -536,15 +537,17 @@ static void draw_histogram(ARegion *region, uchar col_grid[4] = {128, 128, 128, 128}; float grid_x_0 = area.xmin; float grid_x_1 = area.xmax; - /* Float histograms show -0.25 .. 1.25 area horizontally. */ - if (hist.data.size() > 256) { - grid_x_0 = area.xmin + (area.xmax - area.xmin) * (0.25f / 1.5f); - grid_x_1 = area.xmin + (area.xmax - area.xmin) * (1.25f / 1.5f); + /* Float histograms show more than 0..1 range horizontally. */ + if (hist.is_float_hist()) { + float ratio_0 = ratiof(ScopeHistogram::FLOAT_VAL_MIN, ScopeHistogram::FLOAT_VAL_MAX, 0.0f); + float ratio_1 = ratiof(ScopeHistogram::FLOAT_VAL_MIN, ScopeHistogram::FLOAT_VAL_MAX, 1.0f); + grid_x_0 = area.xmin + (area.xmax - area.xmin) * ratio_0; + grid_x_1 = area.xmin + (area.xmax - area.xmin) * ratio_1; } View2D *v2d = ®ion->v2d; - const float text_scale_x = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); - const float text_scale_y = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask); + float text_scale_x, text_scale_y; + UI_view2d_scale_get_inverse(v2d, &text_scale_x, &text_scale_y); for (int line = 0; line <= 4; line++) { float val = float(line) / 4; @@ -553,7 +556,7 @@ static void draw_histogram(ARegion *region, /* Label. */ char buf[10]; - snprintf(buf, sizeof(buf), "%.2f", val); + BLI_snprintf(buf, sizeof(buf), "%.2f", val); size_t buf_len = strlen(buf); float text_width, text_height; @@ -616,7 +619,7 @@ static void draw_waveform_graticule(ARegion *region, SeqQuadsBatch &quads, const for (int i = 0; i < 3; i++) { const float y = area.ymin + (area.ymax - area.ymin) * lines[i]; char buf[10]; - snprintf(buf, sizeof(buf), "%.1f", lines[i]); + BLI_snprintf(buf, sizeof(buf), "%.1f", lines[i]); quads.add_line(x0, y, x1, y, col_grid); UI_view2d_text_cache_add(®ion->v2d, x0 + 8, y + 8, buf, strlen(buf), col_grid); } @@ -681,7 +684,7 @@ static void draw_vectorscope_graticule(SeqQuadsBatch &quads, const rctf &area) /* skin tone line */ uchar col_tone[4] = {255, 102, 0, 128}; - const float tone_line_len = 0.895f; /* makes it end at outer edge of saturation ring */ + const float tone_line_len = 0.895f; /* makes it end at outer edge of saturation ring. */ quads.add_line(centerx, centery, centerx + cosf(skin_rad) * rad_x * tone_line_len, @@ -689,21 +692,16 @@ static void draw_vectorscope_graticule(SeqQuadsBatch &quads, const rctf &area) col_tone); } -static void sequencer_draw_scopes(Scene *scene, ARegion *region, SpaceSeq *sseq, bool draw_overlay) +static void sequencer_draw_scopes(Scene *scene, ARegion *region, SpaceSeq *sseq) { using namespace blender::ed::seq; /* Figure out draw coordinates. */ rctf preview; - sequencer_preview_get_rect(&preview, scene, region, sseq, draw_overlay, false); + sequencer_preview_get_rect(&preview, scene, region, sseq, false, false); rctf uv; - if (draw_overlay && (sseq->overlay_frame_type == SEQ_OVERLAY_FRAME_TYPE_RECT)) { - uv = scene->ed->overlay_frame_rect; - } - else { - BLI_rctf_init(&uv, 0.0f, 1.0f, 0.0f, 1.0f); - } + BLI_rctf_init(&uv, 0.0f, 1.0f, 0.0f, 1.0f); const bool keep_aspect = sseq->mainb == SEQ_DRAW_IMG_VECTORSCOPE; float vecscope_aspect = 1.0f; if (keep_aspect) { @@ -711,10 +709,10 @@ static void sequencer_draw_scopes(Scene *scene, ARegion *region, SpaceSeq *sseq, float height = std::max(BLI_rctf_size_y(&preview), 0.1f); vecscope_aspect = width / height; if (vecscope_aspect >= 1.0f) { - BLI_rctf_resize_x(&uv, BLI_rctf_size_x(&uv) * vecscope_aspect); + BLI_rctf_resize_x(&uv, vecscope_aspect); } else { - BLI_rctf_resize_y(&uv, BLI_rctf_size_y(&uv) / vecscope_aspect); + BLI_rctf_resize_y(&uv, 1.0f / vecscope_aspect); } } @@ -1028,7 +1026,7 @@ void sequencer_draw_preview(const bContext *C, bool has_scope = sequencer_calc_scopes(scene, sseq, ibuf, draw_backdrop); if (has_scope) { /* Draw scope. */ - sequencer_draw_scopes(scene, region, sseq, draw_overlay); + sequencer_draw_scopes(scene, region, sseq); } else { /* Draw image. */ diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.cc b/source/blender/editors/space_sequencer/sequencer_scopes.cc index 7853ee27572..710a71820c5 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.cc +++ b/source/blender/editors/space_sequencer/sequencer_scopes.cc @@ -277,13 +277,10 @@ ImBuf *make_zebra_view_from_ibuf(const ImBuf *ibuf, float perc) static int get_bin_float(float f) { - if (f < -0.25f) { - return 0; - } - if (f >= 1.25f) { - return 511; - } - return int(((f + 0.25f) / 1.5f) * 512); + int bin = int(((f - ScopeHistogram::FLOAT_VAL_MIN) / + (ScopeHistogram::FLOAT_VAL_MAX - ScopeHistogram::FLOAT_VAL_MIN)) * + ScopeHistogram::BINS_FLOAT); + return clamp_i(bin, 0, ScopeHistogram::BINS_FLOAT - 1); } void ScopeHistogram::calc_from_ibuf(const ImBuf *ibuf) @@ -293,7 +290,7 @@ void ScopeHistogram::calc_from_ibuf(const ImBuf *ibuf) #endif const bool is_float = ibuf->float_buffer.data != nullptr; - const int hist_size = is_float ? 512 : 256; + const int hist_size = is_float ? BINS_FLOAT : BINS_BYTE; Array counts(hist_size, uint3(0)); data = threading::parallel_reduce( @@ -304,7 +301,6 @@ void ScopeHistogram::calc_from_ibuf(const ImBuf *ibuf) Array res = init; if (is_float) { - /* Float images spead -0.25..+1.25 range over 512 bins. */ for (const int y : y_range) { const float *src = ibuf->float_buffer.data + y * ibuf->x * 4; for (int x = 0; x < ibuf->x; x++) { diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.hh b/source/blender/editors/space_sequencer/sequencer_scopes.hh index 9fa67047612..85c626f576d 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.hh +++ b/source/blender/editors/space_sequencer/sequencer_scopes.hh @@ -10,33 +10,41 @@ #include "BLI_array.hh" #include "BLI_math_vector_types.hh" +#include "BLI_utility_mixins.hh" struct ImBuf; namespace blender::ed::seq { struct ScopeHistogram { + /* Byte images just have bins for the 0..255 range. */ + static constexpr int BINS_BYTE = 256; + /* Float images spead -0.25..+1.25 range over 512 bins. */ + static constexpr int BINS_FLOAT = 512; + static constexpr float FLOAT_VAL_MIN = -0.25f; + static constexpr float FLOAT_VAL_MAX = 1.25f; Array data; uint3 max_value; void calc_from_ibuf(const ImBuf *ibuf); + bool is_float_hist() const + { + return data.size() == BINS_FLOAT; + } }; -struct SeqScopes { - SeqScopes() = default; - ~SeqScopes(); - SeqScopes(const SeqScopes &) = delete; - void operator=(const SeqScopes &) = delete; - - void cleanup(); - +struct SeqScopes : public NonCopyable { ImBuf *reference_ibuf = nullptr; ImBuf *zebra_ibuf = nullptr; ImBuf *waveform_ibuf = nullptr; ImBuf *sep_waveform_ibuf = nullptr; ImBuf *vector_ibuf = nullptr; - ScopeHistogram histogram; + + SeqScopes() = default; + ~SeqScopes(); + + void cleanup(); }; ImBuf *make_waveform_view_from_ibuf(const ImBuf *ibuf); diff --git a/source/blender/editors/space_sequencer/space_sequencer.cc b/source/blender/editors/space_sequencer/space_sequencer.cc index 85cf3eb37c8..9d673798f6f 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.cc +++ b/source/blender/editors/space_sequencer/space_sequencer.cc @@ -65,7 +65,7 @@ static void sequencer_scopes_tag_refresh(ScrArea *area) sseq->runtime->scopes.reference_ibuf = nullptr; } -SpaceSeq_Runtime::~SpaceSeq_Runtime() +blender::ed::seq::SpaceSeq_Runtime::~SpaceSeq_Runtime() { if (last_displayed_thumbnails != nullptr) { BLI_ghash_free(last_displayed_thumbnails, nullptr, last_displayed_thumbnails_list_free); diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 3de669f62e5..244c7dd59fd 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -66,17 +66,20 @@ namespace blender::ed::outliner { struct SpaceOutliner_Runtime; } // namespace blender::ed::outliner using SpaceOutliner_Runtime = blender::ed::outliner::SpaceOutliner_Runtime; + +namespace blender::ed::seq { +struct SpaceSeq_Runtime; +} // namespace blender::ed::seq +using SpaceSeq_Runtime = blender::ed::seq::SpaceSeq_Runtime; #else typedef struct SpaceNode_Runtime SpaceNode_Runtime; typedef struct SpaceOutliner_Runtime SpaceOutliner_Runtime; +typedef struct SpaceSeq_Runtime SpaceSeq_Runtime; #endif /** Defined in `file_intern.hh`. */ typedef struct SpaceFile_Runtime SpaceFile_Runtime; -/** Defined in `sequencer_intern.hh`. */ -typedef struct SpaceSeq_Runtime SpaceSeq_Runtime; - /** Defined in `spreadsheet_intern.hh`. */ typedef struct SpaceSpreadsheet_Runtime SpaceSpreadsheet_Runtime; -- 2.30.2