diff --git a/libs/ui/kis_animation_frame_cache.cpp b/libs/ui/kis_animation_frame_cache.cpp index df47547491..2fa2f07b2b 100644 --- a/libs/ui/kis_animation_frame_cache.cpp +++ b/libs/ui/kis_animation_frame_cache.cpp @@ -1,239 +1,239 @@ /* * Copyright (c) 2015 Jouni Pentikäinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_animation_frame_cache.h" #include #include "kis_debug.h" #include "kis_image.h" #include "kis_image_animation_interface.h" #include "kis_time_range.h" #include "KisPart.h" #include "kis_animation_cache_populator.h" #include "opengl/kis_opengl_image_textures.h" struct KisAnimationFrameCache::Private { Private(KisOpenGLImageTexturesSP _textures) : textures(_textures) { image = textures->image(); } ~Private() { qDeleteAll(frames); } KisOpenGLImageTexturesSP textures; KisImageWSP image; struct Frame { KisOpenGLUpdateInfoSP openGlFrame; int length; Frame(KisOpenGLUpdateInfoSP info, int length) : openGlFrame(info), length(length) {} }; QMap frames; Frame *getFrame(int time) { if (frames.isEmpty()) return 0; QMap::iterator it = frames.upperBound(time); if (it != frames.begin()) it--; Q_ASSERT(it != frames.end()); int start = it.key(); int length = it.value()->length; if (length == -1) { if (start <= time) return it.value(); } else { int end = start + length - 1; if (start <= time && time <= end) return it.value(); } return 0; } void addFrame(KisOpenGLUpdateInfoSP info, const KisTimeRange& range) { invalidate(range); int length = range.isInfinite() ? -1 : range.end() - range.start() + 1; Frame *frame = new Frame(info, length); frames.insert(range.start(), frame); } /** * Invalidate any cached frames within the given time range. * @param range * @return true if frames were invalidated, false if nothing was changed */ bool invalidate(const KisTimeRange& range) { if (frames.isEmpty()) return false; bool cacheChanged = false; QMap::iterator it = frames.lowerBound(range.start()); if (it.key() != range.start() && it != frames.begin()) it--; while (it != frames.end()) { Frame *frame = it.value(); int start = it.key(); int length = it.value()->length; bool frameIsInfinite = (length == -1); int end = start + length - 1; if (start >= range.start()) { if (!range.isInfinite() && start > range.end()) { break; } if (!range.isInfinite() && (frameIsInfinite || end > range.end())) { // Reinsert with a later start int newStart = range.end() + 1; int newLength = frameIsInfinite ? -1 : (end - newStart + 1); frames.insert(newStart, new Frame(frame->openGlFrame, newLength)); } it = frames.erase(it); delete frame; cacheChanged = true; continue; } else if (frameIsInfinite || end >= range.start()) { int newEnd = range.start() - 1; frame->length = newEnd - start + 1; cacheChanged = true; } it++; } return cacheChanged; } // TODO: verify that we don't have any leak here! typedef QMap CachesMap; static CachesMap caches; }; KisAnimationFrameCache::Private::CachesMap KisAnimationFrameCache::Private::caches; KisAnimationFrameCacheSP KisAnimationFrameCache::getFrameCache(KisOpenGLImageTexturesSP textures) { KisAnimationFrameCache *cache; Private::CachesMap::iterator it = Private::caches.find(textures); if (it == Private::caches.end()) { cache = new KisAnimationFrameCache(textures); Private::caches.insert(textures, cache); } else { cache = it.value(); } return cache; } const QList KisAnimationFrameCache::caches() { return Private::caches.values(); } KisAnimationFrameCache::KisAnimationFrameCache(KisOpenGLImageTexturesSP textures) : m_d(new Private(textures)) { connect(m_d->image->animationInterface(), SIGNAL(sigFramesChanged(KisTimeRange,QRect)), this, SLOT(framesChanged(KisTimeRange,QRect))); } KisAnimationFrameCache::~KisAnimationFrameCache() { Private::caches.remove(m_d->textures); } bool KisAnimationFrameCache::uploadFrame(int time) { Private::Frame *frame = m_d->getFrame(time); if (!frame) { KisPart::instance()->cachePopulator()->regenerate(this, time); } else { m_d->textures->recalculateCache(frame->openGlFrame); } return frame != 0; } KisAnimationFrameCache::CacheStatus KisAnimationFrameCache::frameStatus(int time) const { Private::Frame *frame = m_d->getFrame(time); return (frame) ? Cached : Uncached; } KisImageWSP KisAnimationFrameCache::image() { return m_d->image; } void KisAnimationFrameCache::framesChanged(const KisTimeRange &range, const QRect &rect) { Q_UNUSED(rect); if (!range.isValid()) return; bool cacheChanged = m_d->invalidate(range); if (cacheChanged) { emit changed(); } } KisOpenGLUpdateInfoSP KisAnimationFrameCache::fetchFrameData(int time) const { if (time != m_d->image->animationInterface()->currentTime()) { qWarning() << "WARNING: KisAnimationFrameCache::frameReady image's time doesn't coincide with the requested time!"; qWarning() << " " << ppVar(m_d->image->animationInterface()->currentTime()) << ppVar(time); } - return m_d->textures->updateCacheNoConversion(m_d->image->bounds()); + return m_d->textures->updateCache(m_d->image->bounds()); } void KisAnimationFrameCache::addConvertedFrameData(KisOpenGLUpdateInfoSP info, int time) { KisTimeRange identicalRange = KisTimeRange::infinite(0); KisTimeRange::calculateTimeRangeRecursive(m_d->image->root(), time, identicalRange, true); m_d->addFrame(info, identicalRange); emit changed(); }