Files
test2/source/blender/sequencer/intern/sequence_lookup.cc
Aras Pranckevicius 754495247b VSE: Speedup drawing of the timeline channels sidebar
Drawing the list of channels on the left side of VSE timeline was taking
surprisingly long time (3.5ms in Sprite Fright Edit v135 on Mac M1 Max).
This PR makes them draw in 0.4ms, i.e. 10x faster, by doing two things:

- Stop "search through the whole timeline" work whenever we need to know
  which meta strip (if any) owns some VSE channel. Remember that info in
  the "sequence lookup" that already holds data to speedup similar queries
  (sequence by name, meta by sequence). I.e. this gains "channel owner by
  channel" query hashtable.
- Stop alternating between "regular font glyph cache" and "svg icons glyph
  cache" on each channel row, which incurs a draw call / UI batch flush.
  Instead, draw all the lock/mute widgets first, then all the channel names.

While at it, simplify code related to sequence lookup:
- Use C++ mutex with lock_guard
- Use BLI Map instead of GHash
- Simplify SEQ_sequence_lookup_tag to just SEQ_sequence_lookup_invalidate
- Remove unused SEQ_get_meta_by_seqbase and SEQ_query_all_meta_strips_recursive

Pull Request: https://projects.blender.org/blender/blender/pulls/127913
2024-09-21 14:30:48 +02:00

177 lines
5.1 KiB
C++

/* SPDX-FileCopyrightText: 2021-2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup sequencer
*/
#include "SEQ_sequencer.hh"
#include "sequencer.hh"
#include "DNA_listBase.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "BLI_listbase.h"
#include "BLI_map.hh"
#include "BLI_sys_types.h"
#include "BLI_vector_set.hh"
#include <cstring>
#include <mutex>
#include "MEM_guardedalloc.h"
static std::mutex lookup_lock;
struct SequenceLookup {
blender::Map<std::string, Sequence *> seq_by_name;
blender::Map<const Sequence *, Sequence *> meta_by_seq;
blender::Map<const Sequence *, blender::VectorSet<Sequence *>> effects_by_seq;
blender::Map<const SeqTimelineChannel *, Sequence *> owner_by_channel;
bool is_valid = false;
};
static void seq_sequence_lookup_append_effect(const Sequence *input,
Sequence *effect,
SequenceLookup *lookup)
{
if (input == nullptr) {
return;
}
blender::VectorSet<Sequence *> &effects = lookup->effects_by_seq.lookup_or_add_default(input);
effects.add(effect);
}
static void seq_sequence_lookup_build_effect(Sequence *seq, SequenceLookup *lookup)
{
if ((seq->type & SEQ_TYPE_EFFECT) == 0) {
return;
}
seq_sequence_lookup_append_effect(seq->seq1, seq, lookup);
seq_sequence_lookup_append_effect(seq->seq2, seq, lookup);
}
static void seq_sequence_lookup_build_from_seqbase(Sequence *parent_meta,
const ListBase *seqbase,
SequenceLookup *lookup)
{
if (parent_meta != nullptr) {
LISTBASE_FOREACH (SeqTimelineChannel *, channel, &parent_meta->channels) {
lookup->owner_by_channel.add(channel, parent_meta);
}
}
LISTBASE_FOREACH (Sequence *, seq, seqbase) {
lookup->seq_by_name.add(seq->name + 2, seq);
lookup->meta_by_seq.add(seq, parent_meta);
seq_sequence_lookup_build_effect(seq, lookup);
if (seq->type == SEQ_TYPE_META) {
seq_sequence_lookup_build_from_seqbase(seq, &seq->seqbase, lookup);
}
}
}
static void seq_sequence_lookup_build(const Scene *scene, SequenceLookup *lookup)
{
Editing *ed = SEQ_editing_get(scene);
seq_sequence_lookup_build_from_seqbase(nullptr, &ed->seqbase, lookup);
lookup->is_valid = true;
}
static SequenceLookup *seq_sequence_lookup_new()
{
SequenceLookup *lookup = MEM_new<SequenceLookup>(__func__);
return lookup;
}
static void seq_sequence_lookup_free(SequenceLookup **lookup)
{
MEM_delete(*lookup);
*lookup = nullptr;
}
static void seq_sequence_lookup_rebuild(const Scene *scene, SequenceLookup **lookup)
{
seq_sequence_lookup_free(lookup);
*lookup = seq_sequence_lookup_new();
seq_sequence_lookup_build(scene, *lookup);
}
static void seq_sequence_lookup_update_if_needed(const Scene *scene, SequenceLookup **lookup)
{
if (!scene->ed) {
return;
}
if (*lookup && (*lookup)->is_valid) {
return;
}
seq_sequence_lookup_rebuild(scene, lookup);
}
void SEQ_sequence_lookup_free(const Scene *scene)
{
BLI_assert(scene->ed);
std::lock_guard lock(lookup_lock);
SequenceLookup *lookup = scene->ed->runtime.sequence_lookup;
seq_sequence_lookup_free(&lookup);
}
Sequence *SEQ_sequence_lookup_seq_by_name(const Scene *scene, const char *key)
{
BLI_assert(scene->ed);
std::lock_guard lock(lookup_lock);
seq_sequence_lookup_update_if_needed(scene, &scene->ed->runtime.sequence_lookup);
SequenceLookup *lookup = scene->ed->runtime.sequence_lookup;
return lookup->seq_by_name.lookup_default(key, nullptr);
}
Sequence *seq_sequence_lookup_meta_by_seq(const Scene *scene, const Sequence *key)
{
BLI_assert(scene->ed);
std::lock_guard lock(lookup_lock);
seq_sequence_lookup_update_if_needed(scene, &scene->ed->runtime.sequence_lookup);
SequenceLookup *lookup = scene->ed->runtime.sequence_lookup;
return lookup->meta_by_seq.lookup_default(key, nullptr);
}
blender::Span<Sequence *> seq_sequence_lookup_effects_by_seq(const Scene *scene,
const Sequence *key)
{
BLI_assert(scene->ed);
std::lock_guard lock(lookup_lock);
seq_sequence_lookup_update_if_needed(scene, &scene->ed->runtime.sequence_lookup);
SequenceLookup *lookup = scene->ed->runtime.sequence_lookup;
blender::VectorSet<Sequence *> &effects = lookup->effects_by_seq.lookup_or_add_default(key);
return effects.as_span();
}
Sequence *SEQ_sequence_lookup_owner_by_channel(const Scene *scene,
const SeqTimelineChannel *channel)
{
BLI_assert(scene->ed);
std::lock_guard lock(lookup_lock);
seq_sequence_lookup_update_if_needed(scene, &scene->ed->runtime.sequence_lookup);
SequenceLookup *lookup = scene->ed->runtime.sequence_lookup;
return lookup->owner_by_channel.lookup_default(channel, nullptr);
}
void SEQ_sequence_lookup_invalidate(const Scene *scene)
{
if (scene == nullptr || scene->ed == nullptr) {
return;
}
std::lock_guard lock(lookup_lock);
SequenceLookup *lookup = scene->ed->runtime.sequence_lookup;
if (lookup != nullptr) {
lookup->is_valid = false;
}
}