Rework internals of how VSE caching is done. Primarily to make all the caching logic more understandable from development point of view, but also has several user visible implications (more details in the PR): - Simpler and fewer caching UI options, - Disk cache is gone (primary reason: proxies are kinda the same thing), - VSE cache size set in preferences is actual size used for VSE caches now (previously caching stopped as soon as whole Blender used that much memory, even if some memory usage was not about VSE at all), - Certain scenarios of cache invalidation are faster now. Pull Request: https://projects.blender.org/blender/blender/pulls/137926
179 lines
4.3 KiB
C++
179 lines
4.3 KiB
C++
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup sequencer
|
|
*/
|
|
|
|
#include "BLI_map.hh"
|
|
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_sequence_types.h"
|
|
|
|
#include "IMB_imbuf.hh"
|
|
|
|
#include "intra_frame_cache.hh"
|
|
|
|
namespace blender::seq {
|
|
|
|
struct StripImageMap {
|
|
Map<const Strip *, ImBuf *> map_;
|
|
ImBuf *get(const Strip *strip) const;
|
|
void put(const Strip *strip, ImBuf *image);
|
|
void invalidate(const Strip *strip);
|
|
void clear();
|
|
};
|
|
|
|
struct IntraFrameCache {
|
|
StripImageMap preprocessed;
|
|
StripImageMap composite;
|
|
float timeline_frame = -1.0f;
|
|
int view_id = -1;
|
|
|
|
~IntraFrameCache()
|
|
{
|
|
preprocessed.clear();
|
|
composite.clear();
|
|
}
|
|
};
|
|
|
|
static IntraFrameCache *query_intra_frame_cache(Scene *scene)
|
|
{
|
|
if (scene == nullptr || scene->ed == nullptr) {
|
|
return nullptr;
|
|
}
|
|
return scene->ed->runtime.intra_frame_cache;
|
|
}
|
|
|
|
void intra_frame_cache_invalidate(Scene *scene)
|
|
{
|
|
IntraFrameCache *cache = query_intra_frame_cache(scene);
|
|
if (cache != nullptr) {
|
|
cache->preprocessed.clear();
|
|
cache->composite.clear();
|
|
cache->timeline_frame = -1.0f;
|
|
cache->view_id = -1;
|
|
}
|
|
}
|
|
|
|
void intra_frame_cache_invalidate(Scene *scene, const Strip *strip)
|
|
{
|
|
if (strip == nullptr) {
|
|
return;
|
|
}
|
|
IntraFrameCache *cache = query_intra_frame_cache(scene);
|
|
if (cache != nullptr) {
|
|
cache->preprocessed.invalidate(strip);
|
|
cache->composite.invalidate(strip);
|
|
}
|
|
}
|
|
|
|
void StripImageMap::invalidate(const Strip *strip)
|
|
{
|
|
/* Invalidate this strip, and all strips that are above it. */
|
|
for (auto it = this->map_.items().begin(); it != this->map_.items().end(); it++) {
|
|
const Strip *key = (*it).key;
|
|
if (key == strip || key->machine >= strip->machine) {
|
|
IMB_freeImBuf((*it).value);
|
|
this->map_.remove(it);
|
|
}
|
|
}
|
|
}
|
|
|
|
ImBuf *StripImageMap::get(const Strip *strip) const
|
|
{
|
|
ImBuf *image = this->map_.lookup_default(strip, nullptr);
|
|
if (image != nullptr) {
|
|
IMB_refImBuf(image);
|
|
}
|
|
return image;
|
|
}
|
|
|
|
void StripImageMap::put(const Strip *strip, ImBuf *image)
|
|
{
|
|
BLI_assert(strip != nullptr);
|
|
if (image == nullptr) {
|
|
return;
|
|
}
|
|
ImBuf *existing = this->map_.lookup_default(strip, nullptr);
|
|
if (existing != nullptr) {
|
|
IMB_freeImBuf(existing);
|
|
}
|
|
this->map_.add_overwrite(strip, image);
|
|
IMB_refImBuf(image);
|
|
}
|
|
|
|
void StripImageMap::clear()
|
|
{
|
|
for (const auto &item : this->map_.items()) {
|
|
IMB_freeImBuf(item.value);
|
|
}
|
|
this->map_.clear();
|
|
}
|
|
|
|
ImBuf *intra_frame_cache_get_preprocessed(Scene *scene, const Strip *strip)
|
|
{
|
|
IntraFrameCache *cache = query_intra_frame_cache(scene);
|
|
if (strip == nullptr || cache == nullptr) {
|
|
return nullptr;
|
|
}
|
|
return cache->preprocessed.get(strip);
|
|
}
|
|
|
|
ImBuf *intra_frame_cache_get_composite(Scene *scene, const Strip *strip)
|
|
{
|
|
IntraFrameCache *cache = query_intra_frame_cache(scene);
|
|
if (strip == nullptr || cache == nullptr) {
|
|
return nullptr;
|
|
}
|
|
return cache->composite.get(strip);
|
|
}
|
|
|
|
void intra_frame_cache_put_preprocessed(Scene *scene, const Strip *strip, ImBuf *image)
|
|
{
|
|
if (scene == nullptr || scene->ed == nullptr || strip == nullptr || image == nullptr) {
|
|
return;
|
|
}
|
|
IntraFrameCache *&cache = scene->ed->runtime.intra_frame_cache;
|
|
if (cache == nullptr) {
|
|
cache = MEM_new<IntraFrameCache>(__func__);
|
|
}
|
|
cache->preprocessed.put(strip, image);
|
|
}
|
|
|
|
void intra_frame_cache_put_composite(Scene *scene, const Strip *strip, ImBuf *image)
|
|
{
|
|
if (scene == nullptr || scene->ed == nullptr || strip == nullptr || image == nullptr) {
|
|
return;
|
|
}
|
|
IntraFrameCache *&cache = scene->ed->runtime.intra_frame_cache;
|
|
if (cache == nullptr) {
|
|
cache = MEM_new<IntraFrameCache>(__func__);
|
|
}
|
|
cache->composite.put(strip, image);
|
|
}
|
|
|
|
void intra_frame_cache_destroy(Scene *scene)
|
|
{
|
|
IntraFrameCache *cache = query_intra_frame_cache(scene);
|
|
if (cache != nullptr) {
|
|
MEM_SAFE_DELETE(scene->ed->runtime.intra_frame_cache);
|
|
}
|
|
}
|
|
|
|
void intra_frame_cache_set_cur_frame(Scene *scene, float frame, int view_id)
|
|
{
|
|
IntraFrameCache *cache = query_intra_frame_cache(scene);
|
|
if (cache != nullptr) {
|
|
if (cache->timeline_frame != frame || cache->view_id != view_id) {
|
|
cache->timeline_frame = frame;
|
|
cache->view_id = view_id;
|
|
cache->preprocessed.clear();
|
|
cache->composite.clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace blender::seq
|