mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1122446 - Give cached surfaces a chance to expire, when starting a downscale-during-decode. r=dholbert
This commit is contained in:
parent
b19344d071
commit
65bfa3a6bb
@ -1415,6 +1415,17 @@ void
|
||||
RasterImage::WantDecodedFrames(const nsIntSize& aSize, uint32_t aFlags,
|
||||
bool aShouldSyncNotify)
|
||||
{
|
||||
if (mDownscaleDuringDecode) {
|
||||
// We're about to decode again, which may mean that some of the previous
|
||||
// sizes we've decoded at aren't useful anymore. We can allow them to
|
||||
// expire from the cache by unlocking them here. When the decode finishes,
|
||||
// it will send an invalidation that will cause all instances of this image
|
||||
// to redraw. If this image is locked, any surfaces that are still useful
|
||||
// will become locked again when LookupFrame touches them, and the remainder
|
||||
// will eventually expire.
|
||||
SurfaceCache::UnlockSurfaces(ImageKey(this));
|
||||
}
|
||||
|
||||
if (aShouldSyncNotify) {
|
||||
// We can sync notify, which means we can also sync decode.
|
||||
if (aFlags & FLAG_SYNC_DECODE) {
|
||||
|
@ -532,7 +532,9 @@ public:
|
||||
return DrawableFrameRef();
|
||||
}
|
||||
|
||||
if (!surface->IsLocked()) {
|
||||
if (cache->IsLocked()) {
|
||||
LockSurface(surface);
|
||||
} else {
|
||||
mExpirationTracker.MarkUsed(surface);
|
||||
}
|
||||
|
||||
@ -571,7 +573,9 @@ public:
|
||||
Remove(surface);
|
||||
}
|
||||
|
||||
if (!surface->IsLocked()) {
|
||||
if (cache->IsLocked()) {
|
||||
LockSurface(surface);
|
||||
} else {
|
||||
mExpirationTracker.MarkUsed(surface);
|
||||
}
|
||||
|
||||
@ -607,15 +611,16 @@ public:
|
||||
|
||||
cache->SetLocked(true);
|
||||
|
||||
// Try to lock all the surfaces the per-image cache is holding.
|
||||
cache->ForEach(DoLockSurface, this);
|
||||
// We don't relock this image's existing surfaces right away; instead, the
|
||||
// image should arrange for Lookup() to touch them if they are still useful.
|
||||
}
|
||||
|
||||
void UnlockImage(const ImageKey aImageKey)
|
||||
{
|
||||
nsRefPtr<ImageSurfaceCache> cache = GetImageCache(aImageKey);
|
||||
if (!cache)
|
||||
return; // Already unlocked and removed.
|
||||
if (!cache || !cache->IsLocked()) {
|
||||
return; // Already unlocked.
|
||||
}
|
||||
|
||||
cache->SetLocked(false);
|
||||
|
||||
@ -623,6 +628,20 @@ public:
|
||||
cache->ForEach(DoUnlockSurface, this);
|
||||
}
|
||||
|
||||
void UnlockSurfaces(const ImageKey aImageKey)
|
||||
{
|
||||
nsRefPtr<ImageSurfaceCache> cache = GetImageCache(aImageKey);
|
||||
if (!cache || !cache->IsLocked()) {
|
||||
return; // Already unlocked.
|
||||
}
|
||||
|
||||
// (Note that we *don't* unlock the per-image cache here; that's the
|
||||
// difference between this and UnlockImage.)
|
||||
|
||||
// Unlock all the surfaces the per-image cache is holding.
|
||||
cache->ForEach(DoUnlockSurface, this);
|
||||
}
|
||||
|
||||
void RemoveImage(const ImageKey aImageKey)
|
||||
{
|
||||
nsRefPtr<ImageSurfaceCache> cache = GetImageCache(aImageKey);
|
||||
@ -678,6 +697,20 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void LockSurface(CachedSurface* aSurface)
|
||||
{
|
||||
if (aSurface->GetLifetime() == Lifetime::Transient ||
|
||||
aSurface->IsLocked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
StopTracking(aSurface);
|
||||
|
||||
// Lock the surface. This can fail.
|
||||
aSurface->SetLocked(true);
|
||||
StartTracking(aSurface);
|
||||
}
|
||||
|
||||
static PLDHashOperator DoStopTracking(const SurfaceKey&,
|
||||
CachedSurface* aSurface,
|
||||
void* aCache)
|
||||
@ -686,25 +719,6 @@ public:
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator DoLockSurface(const SurfaceKey&,
|
||||
CachedSurface* aSurface,
|
||||
void* aCache)
|
||||
{
|
||||
if (aSurface->GetLifetime() == Lifetime::Transient ||
|
||||
aSurface->IsLocked()) {
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
auto cache = static_cast<SurfaceCacheImpl*>(aCache);
|
||||
cache->StopTracking(aSurface);
|
||||
|
||||
// Lock the surface. This can fail.
|
||||
aSurface->SetLocked(true);
|
||||
cache->StartTracking(aSurface);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator DoUnlockSurface(const SurfaceKey&,
|
||||
CachedSurface* aSurface,
|
||||
void* aCache)
|
||||
@ -999,6 +1013,15 @@ SurfaceCache::UnlockImage(Image* aImageKey)
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
SurfaceCache::UnlockSurfaces(const ImageKey aImageKey)
|
||||
{
|
||||
if (sInstance) {
|
||||
MutexAutoLock lock(sInstance->GetMutex());
|
||||
return sInstance->UnlockSurfaces(aImageKey);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
SurfaceCache::RemoveSurface(const ImageKey aImageKey,
|
||||
const SurfaceKey& aSurfaceKey)
|
||||
|
@ -149,9 +149,6 @@ MOZ_END_ENUM_CLASS(InsertOutcome)
|
||||
* Any image which stores surfaces in the SurfaceCache *must* ensure that it
|
||||
* calls RemoveImage() before it is destroyed. See the comments for
|
||||
* RemoveImage() for more details.
|
||||
*
|
||||
* SurfaceCache is not thread-safe; it should only be accessed from the main
|
||||
* thread.
|
||||
*/
|
||||
struct SurfaceCache
|
||||
{
|
||||
@ -171,6 +168,9 @@ struct SurfaceCache
|
||||
* Look up the imgFrame containing a surface in the cache and returns a
|
||||
* drawable reference to that imgFrame.
|
||||
*
|
||||
* If the image associated with the surface is locked, then the surface will
|
||||
* be locked before it is returned.
|
||||
*
|
||||
* If the imgFrame was found in the cache, but had stored its surface in a
|
||||
* volatile buffer which was discarded by the OS, then it is automatically
|
||||
* removed from the cache and an empty DrawableFrameRef is returned. Note that
|
||||
@ -200,6 +200,9 @@ struct SurfaceCache
|
||||
* Returned surfaces may vary from the requested surface only in terms of
|
||||
* size, unless @aAlternateFlags is specified.
|
||||
*
|
||||
* If the image associated with the surface is locked, then the surface will
|
||||
* be locked before it is returned.
|
||||
*
|
||||
* @param aImageKey Key data identifying which image the surface belongs to.
|
||||
* @param aSurfaceKey Key data which identifies the ideal surface to return.
|
||||
* @param aAlternateFlags If not Nothing(), a different set of flags than the
|
||||
@ -221,12 +224,20 @@ struct SurfaceCache
|
||||
*
|
||||
* Each surface in the cache has a lifetime, either Transient or Persistent.
|
||||
* Transient surfaces can expire from the cache at any time. Persistent
|
||||
* surfaces can ordinarily also expire from the cache at any time, but if the
|
||||
* image they're associated with is locked, then these surfaces will never
|
||||
* expire. This means that surfaces which cannot be rematerialized should be
|
||||
* inserted with a persistent lifetime *after* the image is locked with
|
||||
* LockImage(); if you use the other order, the surfaces might expire before
|
||||
* LockImage() gets called.
|
||||
* surfaces, on the other hand, will never expire as long as they remain
|
||||
* locked, but if they become unlocked, can expire just like transient
|
||||
* surfaces. When it is first inserted, a persistent surface is locked if its
|
||||
* associated image is locked. When that image is later unlocked, the surface
|
||||
* becomes unlocked too. To become locked again at that point, two things must
|
||||
* happen: the image must become locked again (via LockImage()), and the
|
||||
* surface must be touched again (via one of the Lookup() functions).
|
||||
*
|
||||
* All of this means that a very particular procedure has to be followed for
|
||||
* surfaces which cannot be rematerialized. First, they must be inserted
|
||||
* with a persistent lifetime *after* the image is locked with LockImage(); if
|
||||
* you use the other order, the surfaces might expire before LockImage() gets
|
||||
* called or before the surface is touched again by Lookup(). Second, the
|
||||
* image they are associated with must never be unlocked.
|
||||
*
|
||||
* If a surface cannot be rematerialized, it may be important to know whether
|
||||
* it was inserted into the cache successfully. Insert() returns FAILURE if it
|
||||
@ -276,8 +287,17 @@ struct SurfaceCache
|
||||
static bool CanHold(size_t aSize);
|
||||
|
||||
/**
|
||||
* Locks an image, preventing any of that image's surfaces from expiring
|
||||
* unless they have a transient lifetime.
|
||||
* Locks an image. Any of the image's persistent surfaces which are either
|
||||
* inserted or accessed while the image is locked will not expire.
|
||||
*
|
||||
* Locking an image does not automatically lock that image's existing
|
||||
* surfaces. A call to LockImage() guarantees that persistent surfaces which
|
||||
* are inserted afterward will not expire before the next call to
|
||||
* UnlockImage() or UnlockSurfaces() for that image. Surfaces that are
|
||||
* accessed via Lookup() or LookupBestMatch() after a LockImage() call will
|
||||
* also not expire until the next UnlockImage() or UnlockSurfaces() call for
|
||||
* that image. Any other surfaces owned by the image may expire at any time,
|
||||
* whether they are persistent or transient.
|
||||
*
|
||||
* Regardless of locking, any of an image's surfaces may be removed using
|
||||
* RemoveSurface(), and all of an image's surfaces are removed by
|
||||
@ -302,10 +322,31 @@ struct SurfaceCache
|
||||
* It's OK to call UnlockImage() on an image that's already unlocked; this has
|
||||
* no effect.
|
||||
*
|
||||
* @param aImageKey The image to lock.
|
||||
* @param aImageKey The image to unlock.
|
||||
*/
|
||||
static void UnlockImage(const ImageKey aImageKey);
|
||||
|
||||
/**
|
||||
* Unlocks the existing surfaces of an image, allowing them to expire at any
|
||||
* time.
|
||||
*
|
||||
* This does not unlock the image itself, so accessing the surfaces via
|
||||
* Lookup() or LookupBestMatch() will lock them again, and prevent them from
|
||||
* expiring.
|
||||
*
|
||||
* This is intended to be used in situations where it's no longer clear that
|
||||
* all of the persistent surfaces owned by an image are needed. Calling
|
||||
* UnlockSurfaces() and then taking some action that will cause Lookup() to
|
||||
* touch any surfaces that are still useful will permit the remaining surfaces
|
||||
* to expire from the cache.
|
||||
*
|
||||
* If the image is unlocked, this has no effect.
|
||||
*
|
||||
* @param aImageKey The image which should have its existing surfaces
|
||||
* unlocked.
|
||||
*/
|
||||
static void UnlockSurfaces(const ImageKey aImageKey);
|
||||
|
||||
/**
|
||||
* Removes a surface from the cache, if it's present. If it's not present,
|
||||
* RemoveSurface() has no effect.
|
||||
|
Loading…
Reference in New Issue
Block a user