mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1104622 (Part 1) - Remove DiscardTracker. r=tn
This commit is contained in:
parent
8123b9e88a
commit
b3a334e0e2
@ -329,15 +329,6 @@ pref("media.video-queue.default-size", 3);
|
||||
// optimize images' memory usage
|
||||
pref("image.mem.decodeondraw", true);
|
||||
pref("image.mem.allow_locking_in_content_processes", false); /* don't allow image locking */
|
||||
pref("image.mem.min_discard_timeout_ms", 86400000); /* 24h, we rely on the out of memory hook */
|
||||
// At this point 'max_decoded_image_kb' only applies to animated images. They're
|
||||
// unfortunately fairly large, so this pref still needs to be somewhat generous,
|
||||
// but it makes sense to reduce it since most types of images are now in the
|
||||
// surface cache. Once animated images are stored in the surface cache too, this
|
||||
// pref will go away; see bug 977459. The same goes for
|
||||
// 'hard_limit_decoded_image_kb'; the surface cache limits are all hard.
|
||||
pref("image.mem.max_decoded_image_kb", 30000);
|
||||
pref("image.mem.hard_limit_decoded_image_kb", 66560);
|
||||
// Limit the surface cache to 1/8 of main memory or 128MB, whichever is smaller.
|
||||
// Almost everything that was factored into 'max_decoded_image_kb' is now stored
|
||||
// in the surface cache. 1/8 of main memory is 32MB on a 256MB device, which is
|
||||
|
@ -236,8 +236,6 @@ private:
|
||||
DECL_GFX_PREF(Live, "image.mem.decode_bytes_at_a_time", ImageMemDecodeBytesAtATime, uint32_t, 200000);
|
||||
DECL_GFX_PREF(Live, "image.mem.decodeondraw", ImageMemDecodeOnDraw, bool, false);
|
||||
DECL_GFX_PREF(Live, "image.mem.discardable", ImageMemDiscardable, bool, false);
|
||||
DECL_GFX_PREF(Live, "image.mem.hard_limit_decoded_image_kb", ImageMemHardLimitDecodedImageKB, uint32_t, 0);
|
||||
DECL_GFX_PREF(Live, "image.mem.max_decoded_image_kb", ImageMemMaxDecodedImageKB, uint32_t, 50*1024);
|
||||
DECL_GFX_PREF(Live, "image.mem.max_ms_before_yield", ImageMemMaxMSBeforeYield, uint32_t, 400);
|
||||
DECL_GFX_PREF(Once, "image.mem.surfacecache.discard_factor", ImageMemSurfaceCacheDiscardFactor, uint32_t, 1);
|
||||
DECL_GFX_PREF(Once, "image.mem.surfacecache.max_size_kb", ImageMemSurfaceCacheMaxSizeKB, uint32_t, 100 * 1024);
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "imgRequest.h"
|
||||
#include "imgRequestProxy.h"
|
||||
#include "imgTools.h"
|
||||
#include "DiscardTracker.h"
|
||||
|
||||
#include "nsICOEncoder.h"
|
||||
#include "nsPNGEncoder.h"
|
||||
@ -92,7 +91,6 @@ mozilla::image::InitModule()
|
||||
gfxPrefs::GetSingleton();
|
||||
|
||||
mozilla::image::ShutdownTracker::Initialize();
|
||||
mozilla::image::DiscardTracker::Initialize();
|
||||
mozilla::image::ImageFactory::Initialize();
|
||||
mozilla::image::RasterImage::Initialize();
|
||||
mozilla::image::SurfaceCache::Initialize();
|
||||
@ -109,7 +107,6 @@ mozilla::image::ShutdownModule()
|
||||
}
|
||||
imgLoader::Shutdown();
|
||||
mozilla::image::SurfaceCache::Shutdown();
|
||||
mozilla::image::DiscardTracker::Shutdown();
|
||||
sInitialized = false;
|
||||
}
|
||||
|
||||
|
@ -1,328 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsITimer.h"
|
||||
#include "RasterImage.h"
|
||||
#include "DiscardTracker.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "gfxPrefs.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
static const char* sDiscardTimeoutPref = "image.mem.min_discard_timeout_ms";
|
||||
|
||||
/* static */ LinkedList<DiscardTracker::Node> DiscardTracker::sDiscardableImages;
|
||||
/* static */ nsCOMPtr<nsITimer> DiscardTracker::sTimer;
|
||||
/* static */ bool DiscardTracker::sInitialized = false;
|
||||
/* static */ bool DiscardTracker::sTimerOn = false;
|
||||
/* static */ Atomic<bool> DiscardTracker::sDiscardRunnablePending(false);
|
||||
/* static */ uint64_t DiscardTracker::sCurrentDecodedImageBytes = 0;
|
||||
/* static */ uint32_t DiscardTracker::sMinDiscardTimeoutMs = 10000;
|
||||
/* static */ PRLock * DiscardTracker::sAllocationLock = nullptr;
|
||||
/* static */ Mutex* DiscardTracker::sNodeListMutex = nullptr;
|
||||
/* static */ Atomic<bool> DiscardTracker::sShutdown(false);
|
||||
|
||||
/*
|
||||
* When we notice we're using too much memory for decoded images, we enqueue a
|
||||
* DiscardRunnable, which runs this code.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
DiscardTracker::DiscardRunnable::Run()
|
||||
{
|
||||
sDiscardRunnablePending = false;
|
||||
|
||||
DiscardTracker::DiscardNow();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
DiscardTimeoutChangedCallback(const char* aPref, void *aClosure)
|
||||
{
|
||||
DiscardTracker::ReloadTimeout();
|
||||
}
|
||||
|
||||
nsresult
|
||||
DiscardTracker::Reset(Node *node)
|
||||
{
|
||||
// We shouldn't call Reset() with a null |img| pointer, on images which can't
|
||||
// be discarded, or on animated images (which should be marked as
|
||||
// non-discardable, anyway).
|
||||
MutexAutoLock lock(*sNodeListMutex);
|
||||
MOZ_ASSERT(sInitialized);
|
||||
MOZ_ASSERT(node->img);
|
||||
MOZ_ASSERT(node->img->CanDiscard());
|
||||
MOZ_ASSERT(!node->img->mAnim);
|
||||
|
||||
// Insert the node at the front of the list and note when it was inserted.
|
||||
bool wasInList = node->isInList();
|
||||
if (wasInList) {
|
||||
node->remove();
|
||||
}
|
||||
node->timestamp = TimeStamp::Now();
|
||||
sDiscardableImages.insertFront(node);
|
||||
|
||||
// If the node wasn't already in the list of discardable images, then we may
|
||||
// need to discard some images to stay under gfxPrefs::ImageMemMaxDecodedImageKB() limit.
|
||||
// Call MaybeDiscardSoon to do this check.
|
||||
if (!wasInList) {
|
||||
MaybeDiscardSoon();
|
||||
}
|
||||
|
||||
// Make sure the timer is running.
|
||||
nsresult rv = EnableTimer();
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
DiscardTracker::Remove(Node *node)
|
||||
{
|
||||
if (sShutdown) {
|
||||
// Already shutdown. List should be empty, so just return.
|
||||
return;
|
||||
}
|
||||
MutexAutoLock lock(*sNodeListMutex);
|
||||
|
||||
if (node->isInList())
|
||||
node->remove();
|
||||
|
||||
if (sDiscardableImages.isEmpty())
|
||||
DisableTimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shut down the tracker, deallocating the timer.
|
||||
*/
|
||||
void
|
||||
DiscardTracker::Shutdown()
|
||||
{
|
||||
sShutdown = true;
|
||||
|
||||
if (sTimer) {
|
||||
sTimer->Cancel();
|
||||
sTimer = nullptr;
|
||||
}
|
||||
|
||||
// Clear the sDiscardableImages linked list so that its destructor
|
||||
// (LinkedList.h) finds an empty array, which is required after bug 803688.
|
||||
DiscardAll();
|
||||
|
||||
delete sNodeListMutex;
|
||||
sNodeListMutex = nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Discard all the images we're tracking.
|
||||
*/
|
||||
void
|
||||
DiscardTracker::DiscardAll()
|
||||
{
|
||||
MutexAutoLock lock(*sNodeListMutex);
|
||||
|
||||
if (!sInitialized)
|
||||
return;
|
||||
|
||||
// Be careful: Calling Discard() on an image might cause it to be removed
|
||||
// from the list!
|
||||
Node *n;
|
||||
while ((n = sDiscardableImages.popFirst())) {
|
||||
n->img->Discard();
|
||||
}
|
||||
|
||||
// The list is empty, so there's no need to leave the timer on.
|
||||
DisableTimer();
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
DiscardTracker::TryAllocation(uint64_t aBytes)
|
||||
{
|
||||
MOZ_ASSERT(sInitialized);
|
||||
|
||||
PR_Lock(sAllocationLock);
|
||||
bool enoughSpace =
|
||||
!gfxPrefs::ImageMemHardLimitDecodedImageKB() ||
|
||||
(gfxPrefs::ImageMemHardLimitDecodedImageKB() * 1024) - sCurrentDecodedImageBytes >= aBytes;
|
||||
|
||||
if (enoughSpace) {
|
||||
sCurrentDecodedImageBytes += aBytes;
|
||||
}
|
||||
PR_Unlock(sAllocationLock);
|
||||
|
||||
// If we're using too much memory for decoded images, MaybeDiscardSoon will
|
||||
// enqueue a callback to discard some images.
|
||||
MaybeDiscardSoon();
|
||||
|
||||
return enoughSpace;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
DiscardTracker::InformDeallocation(uint64_t aBytes)
|
||||
{
|
||||
// This function is called back e.g. from RasterImage::Discard(); be careful!
|
||||
|
||||
MOZ_ASSERT(sInitialized);
|
||||
|
||||
PR_Lock(sAllocationLock);
|
||||
MOZ_ASSERT(aBytes <= sCurrentDecodedImageBytes);
|
||||
sCurrentDecodedImageBytes -= aBytes;
|
||||
PR_Unlock(sAllocationLock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the tracker.
|
||||
*/
|
||||
nsresult
|
||||
DiscardTracker::Initialize()
|
||||
{
|
||||
// Watch the timeout pref for changes.
|
||||
Preferences::RegisterCallback(DiscardTimeoutChangedCallback,
|
||||
sDiscardTimeoutPref);
|
||||
|
||||
// Create the timer.
|
||||
sTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
|
||||
// Create a lock for safegarding the 64-bit sCurrentDecodedImageBytes
|
||||
sAllocationLock = PR_NewLock();
|
||||
|
||||
// Create a lock for the node list.
|
||||
MOZ_ASSERT(!sNodeListMutex);
|
||||
sNodeListMutex = new Mutex("image::DiscardTracker");
|
||||
|
||||
// Mark us as initialized
|
||||
sInitialized = true;
|
||||
|
||||
// Read the timeout pref and start the timer.
|
||||
ReloadTimeout();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the discard timeout from about:config.
|
||||
*/
|
||||
void
|
||||
DiscardTracker::ReloadTimeout()
|
||||
{
|
||||
// Read the timeout pref.
|
||||
int32_t discardTimeout;
|
||||
nsresult rv = Preferences::GetInt(sDiscardTimeoutPref, &discardTimeout);
|
||||
|
||||
// If we got something bogus, return.
|
||||
if (!NS_SUCCEEDED(rv) || discardTimeout <= 0)
|
||||
return;
|
||||
|
||||
// If the value didn't change, return.
|
||||
if ((uint32_t) discardTimeout == sMinDiscardTimeoutMs)
|
||||
return;
|
||||
|
||||
// Update the value.
|
||||
sMinDiscardTimeoutMs = (uint32_t) discardTimeout;
|
||||
|
||||
// Restart the timer so the new timeout takes effect.
|
||||
DisableTimer();
|
||||
EnableTimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the timer. No-op if the timer is already running.
|
||||
*/
|
||||
nsresult
|
||||
DiscardTracker::EnableTimer()
|
||||
{
|
||||
// Nothing to do if the timer's already on or we haven't yet been
|
||||
// initialized. !sTimer probably means we've shut down, so just ignore that,
|
||||
// too.
|
||||
if (sTimerOn || !sInitialized || !sTimer)
|
||||
return NS_OK;
|
||||
|
||||
sTimerOn = true;
|
||||
|
||||
// Activate the timer. Have it call us back in (sMinDiscardTimeoutMs / 2)
|
||||
// ms, so that an image is discarded between sMinDiscardTimeoutMs and
|
||||
// (3/2 * sMinDiscardTimeoutMs) ms after it's unlocked.
|
||||
return sTimer->InitWithFuncCallback(TimerCallback,
|
||||
nullptr,
|
||||
sMinDiscardTimeoutMs / 2,
|
||||
nsITimer::TYPE_REPEATING_SLACK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disables the timer. No-op if the timer isn't running.
|
||||
*/
|
||||
void
|
||||
DiscardTracker::DisableTimer()
|
||||
{
|
||||
// Nothing to do if the timer's already off.
|
||||
if (!sTimerOn || !sTimer)
|
||||
return;
|
||||
sTimerOn = false;
|
||||
|
||||
// Deactivate
|
||||
sTimer->Cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Routine activated when the timer fires. This discards everything that's
|
||||
* older than sMinDiscardTimeoutMs, and tries to discard enough images so that
|
||||
* we go under gfxPrefs::ImageMemMaxDecodedImageKB().
|
||||
*/
|
||||
void
|
||||
DiscardTracker::TimerCallback(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
DiscardNow();
|
||||
}
|
||||
|
||||
void
|
||||
DiscardTracker::DiscardNow()
|
||||
{
|
||||
// Assuming the list is ordered with oldest discard tracker nodes at the back
|
||||
// and newest ones at the front, iterate from back to front discarding nodes
|
||||
// until we encounter one which is new enough to keep and until we go under
|
||||
// our gfxPrefs::ImageMemMaxDecodedImageKB() limit.
|
||||
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
Node* node;
|
||||
while ((node = sDiscardableImages.getLast())) {
|
||||
if ((now - node->timestamp).ToMilliseconds() > sMinDiscardTimeoutMs ||
|
||||
sCurrentDecodedImageBytes > gfxPrefs::ImageMemMaxDecodedImageKB() * 1024) {
|
||||
|
||||
// Discarding the image should cause sCurrentDecodedImageBytes to
|
||||
// decrease via a call to InformDeallocation().
|
||||
node->img->Discard();
|
||||
|
||||
// Careful: Discarding may have caused the node to have been removed
|
||||
// from the list.
|
||||
Remove(node);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If the list is empty, disable the timer.
|
||||
if (sDiscardableImages.isEmpty())
|
||||
DisableTimer();
|
||||
}
|
||||
|
||||
void
|
||||
DiscardTracker::MaybeDiscardSoon()
|
||||
{
|
||||
// Are we carrying around too much decoded image data? If so, enqueue an
|
||||
// event to try to get us down under our limit.
|
||||
if (sCurrentDecodedImageBytes > gfxPrefs::ImageMemMaxDecodedImageKB() * 1024 &&
|
||||
!sDiscardableImages.isEmpty()) {
|
||||
// Check if the value of sDiscardRunnablePending used to be false
|
||||
if (!sDiscardRunnablePending.exchange(true)) {
|
||||
nsRefPtr<DiscardRunnable> runnable = new DiscardRunnable();
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace image
|
||||
} // namespace mozilla
|
@ -1,140 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_imagelib_DiscardTracker_h_
|
||||
#define mozilla_imagelib_DiscardTracker_h_
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "prlock.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
class nsITimer;
|
||||
|
||||
namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
class RasterImage;
|
||||
|
||||
/**
|
||||
* This static class maintains a linked list of RasterImage objects which are
|
||||
* eligible for discarding.
|
||||
*
|
||||
* When Reset() is called, the node is removed from its position in the list
|
||||
* (if it was there before) and appended to the beginnings of the list.
|
||||
*
|
||||
* Periodically (on a timer and when we notice that we're using more memory
|
||||
* than we'd like for decoded images), we go through the list and discard
|
||||
* decoded data from images at the end of the list.
|
||||
*/
|
||||
class DiscardTracker
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The DiscardTracker keeps a linked list of Node objects. Each object
|
||||
* points to a RasterImage and contains a timestamp indicating when the
|
||||
* node was inserted into the tracker.
|
||||
*
|
||||
* This structure is embedded within each RasterImage object, and we do
|
||||
* |mDiscardTrackerNode.img = this| on RasterImage construction. Thus, a
|
||||
* RasterImage must always call DiscardTracker::Remove() in its destructor
|
||||
* to avoid having the tracker point to bogus memory.
|
||||
*/
|
||||
struct Node : public LinkedListElement<Node>
|
||||
{
|
||||
RasterImage *img;
|
||||
TimeStamp timestamp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add an image to the front of the tracker's list, or move it to the front
|
||||
* if it's already in the list. This function is main thread only.
|
||||
*/
|
||||
static nsresult Reset(struct Node* node);
|
||||
|
||||
/**
|
||||
* Remove a node from the tracker; do nothing if the node is currently
|
||||
* untracked. This function is main thread only.
|
||||
*/
|
||||
static void Remove(struct Node* node);
|
||||
|
||||
/**
|
||||
* Initializes the discard tracker. This function is main thread only.
|
||||
*/
|
||||
static nsresult Initialize();
|
||||
|
||||
/**
|
||||
* Shut the discard tracker down. This should be called on XPCOM shutdown
|
||||
* so we destroy the discard timer's nsITimer. This function is main thread
|
||||
* only.
|
||||
*/
|
||||
static void Shutdown();
|
||||
|
||||
/**
|
||||
* Discard the decoded image data for all images tracked by the discard
|
||||
* tracker. This function is main thread only.
|
||||
*/
|
||||
static void DiscardAll();
|
||||
|
||||
/**
|
||||
* Inform the discard tracker that we are going to allocate some memory
|
||||
* for a decoded image. We use this to determine when we've allocated
|
||||
* too much memory and should discard some images. This function can be
|
||||
* called from any thread and is thread-safe. If this function succeeds, the
|
||||
* caller is now responsible for ensuring that InformDeallocation is called.
|
||||
*/
|
||||
static bool TryAllocation(uint64_t aBytes);
|
||||
|
||||
/**
|
||||
* Inform the discard tracker that we've deallocated some memory for a
|
||||
* decoded image. This function can be called from any thread and is
|
||||
* thread-safe.
|
||||
*/
|
||||
static void InformDeallocation(uint64_t aBytes);
|
||||
|
||||
private:
|
||||
/**
|
||||
* This is called when the discard timer fires; it calls into DiscardNow().
|
||||
*/
|
||||
friend void DiscardTimeoutChangedCallback(const char* aPref, void *aClosure);
|
||||
|
||||
/**
|
||||
* When run, this runnable sets sDiscardRunnablePending to false and calls
|
||||
* DiscardNow().
|
||||
*/
|
||||
class DiscardRunnable : public nsRunnable
|
||||
{
|
||||
NS_IMETHOD Run();
|
||||
};
|
||||
|
||||
static void ReloadTimeout();
|
||||
static nsresult EnableTimer();
|
||||
static void DisableTimer();
|
||||
static void MaybeDiscardSoon();
|
||||
static void TimerCallback(nsITimer *aTimer, void *aClosure);
|
||||
static void DiscardNow();
|
||||
|
||||
static LinkedList<Node> sDiscardableImages;
|
||||
static nsCOMPtr<nsITimer> sTimer;
|
||||
static bool sInitialized;
|
||||
static bool sTimerOn;
|
||||
static Atomic<bool> sDiscardRunnablePending;
|
||||
static uint64_t sCurrentDecodedImageBytes;
|
||||
static uint32_t sMinDiscardTimeoutMs;
|
||||
static uint32_t sMaxDecodedImageKB;
|
||||
static uint32_t sHardLimitDecodedImageKB;
|
||||
// Lock for safegarding the 64-bit sCurrentDecodedImageBytes
|
||||
static PRLock *sAllocationLock;
|
||||
static Mutex* sNodeListMutex;
|
||||
static Atomic<bool> sShutdown;
|
||||
};
|
||||
|
||||
} // namespace image
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_imagelib_DiscardTracker_h_ */
|
@ -98,6 +98,10 @@ DynamicImage::OnNewSourceData()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
DynamicImage::OnSurfaceDiscarded()
|
||||
{ }
|
||||
|
||||
void
|
||||
DynamicImage::SetInnerWindowID(uint64_t aInnerWindowId)
|
||||
{ }
|
||||
|
@ -58,6 +58,8 @@ public:
|
||||
bool aLastPart) MOZ_OVERRIDE;
|
||||
virtual nsresult OnNewSourceData() MOZ_OVERRIDE;
|
||||
|
||||
virtual void OnSurfaceDiscarded() MOZ_OVERRIDE;
|
||||
|
||||
virtual void SetInnerWindowID(uint64_t aInnerWindowId) MOZ_OVERRIDE;
|
||||
virtual uint64_t InnerWindowID() const MOZ_OVERRIDE;
|
||||
|
||||
|
@ -127,6 +127,12 @@ public:
|
||||
*/
|
||||
virtual nsresult OnNewSourceData() = 0;
|
||||
|
||||
/**
|
||||
* Called when the SurfaceCache discards a persistent surface belonging to
|
||||
* this image.
|
||||
*/
|
||||
virtual void OnSurfaceDiscarded() = 0;
|
||||
|
||||
virtual void SetInnerWindowID(uint64_t aInnerWindowId) = 0;
|
||||
virtual uint64_t InnerWindowID() const = 0;
|
||||
|
||||
@ -156,6 +162,8 @@ public:
|
||||
virtual uint32_t GetAnimationConsumers() MOZ_OVERRIDE { return mAnimationConsumers; }
|
||||
#endif
|
||||
|
||||
virtual void OnSurfaceDiscarded() MOZ_OVERRIDE { }
|
||||
|
||||
virtual void SetInnerWindowID(uint64_t aInnerWindowId) MOZ_OVERRIDE {
|
||||
mInnerWindowId = aInnerWindowId;
|
||||
}
|
||||
|
@ -102,6 +102,12 @@ ImageWrapper::OnNewSourceData()
|
||||
return mInnerImage->OnNewSourceData();
|
||||
}
|
||||
|
||||
void
|
||||
ImageWrapper::OnSurfaceDiscarded()
|
||||
{
|
||||
return mInnerImage->OnSurfaceDiscarded();
|
||||
}
|
||||
|
||||
void
|
||||
ImageWrapper::SetInnerWindowID(uint64_t aInnerWindowId)
|
||||
{
|
||||
|
@ -47,6 +47,8 @@ public:
|
||||
bool aLastPart) MOZ_OVERRIDE;
|
||||
virtual nsresult OnNewSourceData() MOZ_OVERRIDE;
|
||||
|
||||
virtual void OnSurfaceDiscarded() MOZ_OVERRIDE;
|
||||
|
||||
virtual void SetInnerWindowID(uint64_t aInnerWindowId) MOZ_OVERRIDE;
|
||||
virtual uint64_t InnerWindowID() const MOZ_OVERRIDE;
|
||||
|
||||
|
@ -136,22 +136,6 @@ static int num_discardable_containers;
|
||||
static int64_t total_source_bytes;
|
||||
static int64_t discardable_source_bytes;
|
||||
|
||||
/* Are we globally disabling image discarding? */
|
||||
static bool
|
||||
DiscardingEnabled()
|
||||
{
|
||||
static bool inited;
|
||||
static bool enabled;
|
||||
|
||||
if (!inited) {
|
||||
inited = true;
|
||||
|
||||
enabled = (PR_GetEnv("MOZ_DISABLE_IMAGE_DISCARD") == nullptr);
|
||||
}
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
class ScaleRunner : public nsRunnable
|
||||
{
|
||||
enum ScaleState
|
||||
@ -328,8 +312,6 @@ RasterImage::RasterImage(ProgressTracker* aProgressTracker,
|
||||
{
|
||||
mProgressTrackerInit = new ProgressTrackerInit(this, aProgressTracker);
|
||||
|
||||
// Set up the discard tracker node.
|
||||
mDiscardTrackerNode.img = this;
|
||||
Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(0);
|
||||
|
||||
// Statistics
|
||||
@ -371,10 +353,6 @@ RasterImage::~RasterImage()
|
||||
// Total statistics
|
||||
num_containers--;
|
||||
total_source_bytes -= mSourceData.Length();
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
DiscardTracker::Remove(&mDiscardTrackerNode);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
@ -603,8 +581,8 @@ RasterImage::LookupFrame(uint32_t aFrameNum,
|
||||
if (!ref) {
|
||||
// The OS threw this frame away. We need to discard and redecode.
|
||||
MOZ_ASSERT(!mAnim, "Animated frames should be locked");
|
||||
if (CanForciblyDiscardAndRedecode()) {
|
||||
Discard(/* aForce = */ true, /* aNotify = */ false);
|
||||
if (CanDiscard()) {
|
||||
Discard(/* aNotify = */ false);
|
||||
ApplyDecodeFlags(aFlags);
|
||||
WantDecodedFrames(aFlags, aShouldSyncNotify);
|
||||
|
||||
@ -706,6 +684,14 @@ RasterImage::FrameRect(uint32_t aWhichFrame)
|
||||
return nsIntRect();
|
||||
}
|
||||
|
||||
void
|
||||
RasterImage::OnSurfaceDiscarded()
|
||||
{
|
||||
if (mProgressTracker) {
|
||||
mProgressTracker->OnDiscard();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
RasterImage::GetNumFrames() const
|
||||
{
|
||||
@ -940,7 +926,7 @@ RasterImage::GetImageContainer(LayerManager* aManager, ImageContainer **_retval)
|
||||
NS_ADDREF(*_retval);
|
||||
// We only need to be careful about holding on to the image when it is
|
||||
// discardable by the OS.
|
||||
if (CanForciblyDiscardAndRedecode()) {
|
||||
if (CanDiscard()) {
|
||||
mImageContainerCache = mImageContainer;
|
||||
mImageContainer = nullptr;
|
||||
}
|
||||
@ -1120,11 +1106,13 @@ RasterImage::ApplyDecodeFlags(uint32_t aNewFlags)
|
||||
// if we can't discard, then we're screwed; we have no way
|
||||
// to re-decode. Similarly if we aren't allowed to do a sync
|
||||
// decode.
|
||||
if (!(aNewFlags & FLAG_SYNC_DECODE))
|
||||
if (!(aNewFlags & FLAG_SYNC_DECODE)) {
|
||||
return false;
|
||||
if (!CanForciblyDiscardAndRedecode())
|
||||
}
|
||||
if (!CanDiscard()) {
|
||||
return false;
|
||||
ForceDiscard();
|
||||
}
|
||||
Discard();
|
||||
}
|
||||
|
||||
mFrameDecodeFlags = aNewFlags & DECODE_FLAGS_MASK;
|
||||
@ -1237,13 +1225,6 @@ RasterImage::DecodingComplete(imgFrame* aFinalFrame)
|
||||
mDecoded = true;
|
||||
mHasBeenDecoded = true;
|
||||
|
||||
// We now have one of the qualifications for discarding. Re-evaluate.
|
||||
if (CanDiscard()) {
|
||||
NS_ABORT_IF_FALSE(!DiscardingActive(),
|
||||
"We shouldn't have been discardable before this");
|
||||
DiscardTracker::Reset(&mDiscardTrackerNode);
|
||||
}
|
||||
|
||||
bool singleFrame = GetNumFrames() == 1;
|
||||
|
||||
// If there's only 1 frame, mark it as optimizable. Optimizing animated images
|
||||
@ -1572,11 +1553,6 @@ RasterImage::DoImageDataComplete()
|
||||
mSourceData.Length()));
|
||||
}
|
||||
|
||||
// We now have one of the qualifications for discarding. Re-evaluate.
|
||||
if (CanDiscard()) {
|
||||
nsresult rv = DiscardTracker::Reset(&mDiscardTrackerNode);
|
||||
CONTAINER_ENSURE_SUCCESS(rv);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1737,12 +1713,11 @@ RasterImage::GetKeys(uint32_t *count, char ***keys)
|
||||
}
|
||||
|
||||
void
|
||||
RasterImage::Discard(bool aForce, bool aNotify)
|
||||
RasterImage::Discard(bool aNotify)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// We should be ok for discard
|
||||
NS_ABORT_IF_FALSE(aForce ? CanForciblyDiscard() : CanDiscard(), "Asked to discard but can't!");
|
||||
MOZ_ASSERT(CanDiscard(), "Asked to discard but can't");
|
||||
|
||||
// We should never discard when we have an active decoder
|
||||
NS_ABORT_IF_FALSE(!mDecoder, "Asked to discard with open decoder!");
|
||||
@ -1772,10 +1747,6 @@ RasterImage::Discard(bool aForce, bool aNotify)
|
||||
|
||||
mDecodeStatus = DecodeStatus::INACTIVE;
|
||||
|
||||
if (aForce) {
|
||||
DiscardTracker::Remove(&mDiscardTrackerNode);
|
||||
}
|
||||
|
||||
// Log
|
||||
PR_LOG(GetCompressedImageAccountingLog(), PR_LOG_DEBUG,
|
||||
("CompressedImageAccounting: discarded uncompressed image "
|
||||
@ -1792,35 +1763,13 @@ RasterImage::Discard(bool aForce, bool aNotify)
|
||||
discardable_source_bytes));
|
||||
}
|
||||
|
||||
// Helper method to determine if we can discard an image
|
||||
bool
|
||||
RasterImage::CanDiscard() {
|
||||
return (DiscardingEnabled() && // Globally enabled...
|
||||
mDiscardable && // ...Enabled at creation time...
|
||||
(mLockCount == 0) && // ...not temporarily disabled...
|
||||
mHasSourceData && // ...have the source data...
|
||||
mDecoded); // ...and have something to discard.
|
||||
}
|
||||
|
||||
bool
|
||||
RasterImage::CanForciblyDiscard() {
|
||||
return mHasSourceData; // ...have the source data...
|
||||
}
|
||||
|
||||
bool
|
||||
RasterImage::CanForciblyDiscardAndRedecode() {
|
||||
return mHasSourceData && // ...have the source data...
|
||||
!mDecoder && // Can't discard with an open decoder
|
||||
!mAnim; // Can never discard animated images
|
||||
}
|
||||
|
||||
// Helper method to tell us whether the clock is currently running for
|
||||
// discarding this image. Mainly for assertions.
|
||||
bool
|
||||
RasterImage::DiscardingActive() {
|
||||
return mDiscardTrackerNode.isInList();
|
||||
}
|
||||
|
||||
// Helper method to determine if we're storing the source data in a buffer
|
||||
// or just writing it directly to the decoder
|
||||
bool
|
||||
@ -1840,9 +1789,6 @@ RasterImage::InitDecoder(bool aDoSizeDecode)
|
||||
// We shouldn't be firing up a decoder if we already have the frames decoded
|
||||
NS_ABORT_IF_FALSE(!mDecoded, "Calling InitDecoder() but already decoded!");
|
||||
|
||||
// Since we're not decoded, we should not have a discard timer active
|
||||
NS_ABORT_IF_FALSE(!DiscardingActive(), "Discard Timer active in InitDecoder()!");
|
||||
|
||||
// Make sure we actually get size before doing a full decode.
|
||||
if (!aDoSizeDecode) {
|
||||
NS_ABORT_IF_FALSE(mHasSize, "Must do a size decode before a full decode!");
|
||||
@ -1995,16 +1941,6 @@ RasterImage::WriteToDecoder(const char *aBuffer, uint32_t aCount, DecodeStrategy
|
||||
nsresult
|
||||
RasterImage::WantDecodedFrames(uint32_t aFlags, bool aShouldSyncNotify)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// If we can discard, the clock should be running. Reset it.
|
||||
if (CanDiscard()) {
|
||||
NS_ABORT_IF_FALSE(DiscardingActive(),
|
||||
"Decoded and discardable but discarding not activated!");
|
||||
rv = DiscardTracker::Reset(&mDiscardTrackerNode);
|
||||
CONTAINER_ENSURE_SUCCESS(rv);
|
||||
}
|
||||
|
||||
// Request a decode, which does nothing if we're already decoded.
|
||||
if (aShouldSyncNotify) {
|
||||
// We can sync notify, which means we can also sync decode.
|
||||
@ -2230,9 +2166,10 @@ RasterImage::SyncDecode()
|
||||
// If we've finished decoding we need to discard so we can re-decode
|
||||
// with the new flags. If we can't discard then there isn't
|
||||
// anything we can do.
|
||||
if (!CanForciblyDiscardAndRedecode())
|
||||
if (!CanDiscard()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
ForceDiscard();
|
||||
}
|
||||
Discard();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2452,24 +2389,14 @@ RasterImage::Draw(gfxContext* aContext,
|
||||
(mFrameDecodeFlags == FLAG_DECODE_NO_PREMULTIPLY_ALPHA) && IsOpaque();
|
||||
|
||||
if (!(haveDefaultFlags || haveSafeAlphaFlags)) {
|
||||
if (!CanForciblyDiscardAndRedecode())
|
||||
if (!CanDiscard()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
ForceDiscard();
|
||||
}
|
||||
Discard();
|
||||
|
||||
mFrameDecodeFlags = DECODE_FLAGS_DEFAULT;
|
||||
}
|
||||
|
||||
// If this image is a candidate for discarding, reset its position in the
|
||||
// discard tracker so we're less likely to discard it right away.
|
||||
//
|
||||
// (We don't normally draw unlocked images, so this conditition will usually
|
||||
// be false. But we will draw unlocked images if image locking is globally
|
||||
// disabled via the image.mem.allow_locking_in_content_processes pref.)
|
||||
if (DiscardingActive()) {
|
||||
DiscardTracker::Reset(&mDiscardTrackerNode);
|
||||
}
|
||||
|
||||
|
||||
if (IsUnlocked() && mProgressTracker) {
|
||||
mProgressTracker->OnUnlockedDraw();
|
||||
}
|
||||
@ -2520,9 +2447,6 @@ RasterImage::LockImage()
|
||||
if (mError)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Cancel the discard timer if it's there
|
||||
DiscardTracker::Remove(&mDiscardTrackerNode);
|
||||
|
||||
// Increment the lock count
|
||||
mLockCount++;
|
||||
|
||||
@ -2550,9 +2474,6 @@ RasterImage::UnlockImage()
|
||||
if (mLockCount == 0)
|
||||
return NS_ERROR_ABORT;
|
||||
|
||||
// We're locked, so discarding should not be active
|
||||
NS_ABORT_IF_FALSE(!DiscardingActive(), "Locked, but discarding activated");
|
||||
|
||||
// Decrement our lock count
|
||||
mLockCount--;
|
||||
|
||||
@ -2566,23 +2487,16 @@ RasterImage::UnlockImage()
|
||||
// decoded data around), try to cancel the decode and throw away whatever
|
||||
// we've decoded.
|
||||
if (mHasBeenDecoded && mDecoder &&
|
||||
mLockCount == 0 && CanForciblyDiscard()) {
|
||||
mLockCount == 0 && CanDiscard()) {
|
||||
PR_LOG(GetCompressedImageAccountingLog(), PR_LOG_DEBUG,
|
||||
("RasterImage[0x%p] canceling decode because image "
|
||||
"is now unlocked.", this));
|
||||
ReentrantMonitorAutoEnter lock(mDecodingMonitor);
|
||||
FinishedSomeDecoding(ShutdownReason::NOT_NEEDED);
|
||||
ForceDiscard();
|
||||
Discard();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Otherwise, we might still be a candidate for discarding in the future. If
|
||||
// we are, add ourselves to the discard tracker.
|
||||
if (CanDiscard()) {
|
||||
nsresult rv = DiscardTracker::Reset(&mDiscardTrackerNode);
|
||||
CONTAINER_ENSURE_SUCCESS(rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2591,8 +2505,11 @@ RasterImage::UnlockImage()
|
||||
NS_IMETHODIMP
|
||||
RasterImage::RequestDiscard()
|
||||
{
|
||||
if (CanDiscard() && CanForciblyDiscardAndRedecode()) {
|
||||
ForceDiscard();
|
||||
if (mDiscardable && // Enabled at creation time...
|
||||
mLockCount == 0 && // ...not temporarily disabled...
|
||||
mDecoded && // ...and have something to discard.
|
||||
CanDiscard()) {
|
||||
Discard();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include "imgFrame.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "DecodePool.h"
|
||||
#include "DiscardTracker.h"
|
||||
#include "Orientation.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
@ -161,6 +160,7 @@ public:
|
||||
nsresult Init(const char* aMimeType,
|
||||
uint32_t aFlags);
|
||||
virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
|
||||
virtual void OnSurfaceDiscarded() MOZ_OVERRIDE;
|
||||
|
||||
// Raster-specific methods
|
||||
static NS_METHOD WriteToRasterImage(nsIInputStream* aIn, void* aClosure,
|
||||
@ -176,8 +176,7 @@ public:
|
||||
MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
/* Triggers discarding. */
|
||||
void Discard(bool aForce = false, bool aNotify = true);
|
||||
void ForceDiscard() { Discard(/* aForce = */ true); }
|
||||
void Discard(bool aNotify = true);
|
||||
|
||||
/* Callbacks for decoders */
|
||||
/** Sets the size and inherent orientation of the container. This should only
|
||||
@ -364,15 +363,12 @@ private: // data
|
||||
// we maybe decoding on draw).
|
||||
UniquePtr<FrameAnimator> mAnim;
|
||||
|
||||
// Discard members
|
||||
// Image locking.
|
||||
uint32_t mLockCount;
|
||||
DiscardTracker::Node mDiscardTrackerNode;
|
||||
|
||||
// Source data members
|
||||
nsCString mSourceDataMimeType;
|
||||
|
||||
friend class DiscardTracker;
|
||||
|
||||
// How many times we've decoded this image.
|
||||
// This is currently only used for statistics
|
||||
int32_t mDecodeCount;
|
||||
@ -497,9 +493,6 @@ private: // data
|
||||
|
||||
// Helpers
|
||||
bool CanDiscard();
|
||||
bool CanForciblyDiscard();
|
||||
bool CanForciblyDiscardAndRedecode();
|
||||
bool DiscardingActive();
|
||||
bool StoringSourceData() const;
|
||||
|
||||
protected:
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "imgFrame.h"
|
||||
#include "Image.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsExpirationTracker.h"
|
||||
#include "nsHashKeys.h"
|
||||
@ -351,11 +352,16 @@ public:
|
||||
void Remove(CachedSurface* aSurface)
|
||||
{
|
||||
MOZ_ASSERT(aSurface, "Should have a surface");
|
||||
const ImageKey imageKey = aSurface->GetImageKey();
|
||||
ImageKey imageKey = aSurface->GetImageKey();
|
||||
|
||||
nsRefPtr<ImageSurfaceCache> cache = GetImageCache(imageKey);
|
||||
MOZ_ASSERT(cache, "Shouldn't try to remove a surface with no image cache");
|
||||
|
||||
// If the surface was persistent, tell its image that we discarded it.
|
||||
if (aSurface->GetLifetime() == Lifetime::Persistent) {
|
||||
static_cast<Image*>(imageKey)->OnSurfaceDiscarded();
|
||||
}
|
||||
|
||||
StopTracking(aSurface);
|
||||
cache->Remove(aSurface);
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
#include "imgFrame.h"
|
||||
#include "ImageRegion.h"
|
||||
#include "DiscardTracker.h"
|
||||
#include "ShutdownTracker.h"
|
||||
|
||||
#include "prenv.h"
|
||||
@ -20,6 +19,7 @@ static bool gDisableOptimize = false;
|
||||
|
||||
#include "GeckoProfiler.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "nsMargin.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
@ -140,8 +140,7 @@ imgFrame::imgFrame() :
|
||||
mCompositingFailed(false),
|
||||
mHasNoAlpha(false),
|
||||
mNonPremult(false),
|
||||
mOptimizable(false),
|
||||
mInformedDiscardTracker(false)
|
||||
mOptimizable(false)
|
||||
{
|
||||
static bool hasCheckedOptimize = false;
|
||||
if (!hasCheckedOptimize) {
|
||||
@ -156,10 +155,6 @@ imgFrame::~imgFrame()
|
||||
{
|
||||
moz_free(mPalettedImageData);
|
||||
mPalettedImageData = nullptr;
|
||||
|
||||
if (mInformedDiscardTracker) {
|
||||
DiscardTracker::InformDeallocation(4 * mSize.height * mSize.width);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -198,13 +193,6 @@ imgFrame::InitForDecoder(const nsIntSize& aImageSize,
|
||||
} else {
|
||||
MOZ_ASSERT(!mImageSurface, "Called imgFrame::InitForDecoder() twice?");
|
||||
|
||||
// Inform the discard tracker that we are going to allocate some memory.
|
||||
mInformedDiscardTracker =
|
||||
DiscardTracker::TryAllocation(4 * mSize.width * mSize.height);
|
||||
if (!mInformedDiscardTracker) {
|
||||
NS_WARNING("Exceeded the image decode size hard limit");
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
mVBuf = AllocateBufferForImage(mSize, mFormat);
|
||||
if (!mVBuf) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
@ -246,14 +234,6 @@ imgFrame::InitWithDrawable(gfxDrawable* aDrawable,
|
||||
mFormat = aFormat;
|
||||
mPaletteDepth = 0;
|
||||
|
||||
// Inform the discard tracker that we are going to allocate some memory.
|
||||
mInformedDiscardTracker =
|
||||
DiscardTracker::TryAllocation(4 * mSize.width * mSize.height);
|
||||
if (!mInformedDiscardTracker) {
|
||||
NS_WARNING("Exceed the image decode size hard limit");
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> target;
|
||||
|
||||
bool canUseDataSurface =
|
||||
@ -368,13 +348,6 @@ nsresult imgFrame::Optimize()
|
||||
mImageSurface = nullptr;
|
||||
mOptSurface = nullptr;
|
||||
|
||||
// We just dumped most of our allocated memory, so tell the discard
|
||||
// tracker that we're not using any at all.
|
||||
if (mInformedDiscardTracker) {
|
||||
DiscardTracker::InformDeallocation(4 * mSize.width * mSize.height);
|
||||
mInformedDiscardTracker = false;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
@ -207,9 +207,6 @@ private: // data
|
||||
bool mNonPremult;
|
||||
bool mOptimizable;
|
||||
|
||||
/** Have we called DiscardTracker::InformAllocation()? */
|
||||
bool mInformedDiscardTracker;
|
||||
|
||||
friend class DrawableFrameRef;
|
||||
friend class RawAccessFrameRef;
|
||||
};
|
||||
|
@ -36,7 +36,6 @@
|
||||
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "Image.h"
|
||||
#include "DiscardTracker.h"
|
||||
#include "gfxPrefs.h"
|
||||
|
||||
// we want to explore making the document own the load group
|
||||
@ -955,27 +954,6 @@ nsresult imgLoader::CreateNewProxyForRequest(imgRequest *aRequest, nsILoadGroup
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class imgCacheObserver MOZ_FINAL : public nsIObserver
|
||||
{
|
||||
~imgCacheObserver() {}
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(imgCacheObserver, nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
imgCacheObserver::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aSomeData)
|
||||
{
|
||||
if (strcmp(aTopic, "memory-pressure") == 0 ||
|
||||
strcmp(aTopic, "app-theme-changed") == 0) {
|
||||
DiscardTracker::DiscardAll();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class imgCacheExpirationTracker MOZ_FINAL
|
||||
: public nsExpirationTracker<imgCacheEntry, 3>
|
||||
{
|
||||
@ -1016,8 +994,6 @@ void imgCacheExpirationTracker::NotifyExpired(imgCacheEntry *entry)
|
||||
entry->Loader()->VerifyCacheSizes();
|
||||
}
|
||||
|
||||
imgCacheObserver *gCacheObserver;
|
||||
|
||||
double imgLoader::sCacheTimeWeight;
|
||||
uint32_t imgLoader::sCacheMaxSize;
|
||||
imgMemoryReporter* imgLoader::sMemReporter;
|
||||
@ -1138,15 +1114,6 @@ imgCacheQueue & imgLoader::GetCacheQueue(ImageURL *aURI)
|
||||
|
||||
void imgLoader::GlobalInit()
|
||||
{
|
||||
gCacheObserver = new imgCacheObserver();
|
||||
NS_ADDREF(gCacheObserver);
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (os) {
|
||||
os->AddObserver(gCacheObserver, "memory-pressure", false);
|
||||
os->AddObserver(gCacheObserver, "app-theme-changed", false);
|
||||
}
|
||||
|
||||
sCacheTimeWeight = gfxPrefs::ImageCacheTimeWeight() / 1000.0;
|
||||
int32_t cachesize = gfxPrefs::ImageCacheSize();
|
||||
sCacheMaxSize = cachesize > 0 ? cachesize : 0;
|
||||
@ -1284,7 +1251,6 @@ void imgLoader::Shutdown()
|
||||
{
|
||||
NS_IF_RELEASE(gSingleton);
|
||||
NS_IF_RELEASE(gPBSingleton);
|
||||
NS_RELEASE(gCacheObserver);
|
||||
}
|
||||
|
||||
nsresult imgLoader::ClearChromeImageCache()
|
||||
|
@ -18,7 +18,6 @@ UNIFIED_SOURCES += [
|
||||
'ClippedImage.cpp',
|
||||
'DecodePool.cpp',
|
||||
'Decoder.cpp',
|
||||
'DiscardTracker.cpp',
|
||||
'DynamicImage.cpp',
|
||||
'FrameAnimator.cpp',
|
||||
'FrameBlender.cpp',
|
||||
|
@ -19,25 +19,35 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=399925
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/** Test for Bug 399925. **/
|
||||
var triggerDiscardingManually = false;
|
||||
var pngResults = new Array();
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
window.onload = function() {
|
||||
// 1. Enable Discarding
|
||||
// 2. Sets the discard timer to 500ms so we don't have to wait so long. The
|
||||
// actual time is nondeterministic, but is bounded by 2 * timer = 1 second.
|
||||
// It'd be nice to reduce the discard timer here, but unfortunately we only
|
||||
// read that pref on startup. We instead manually trigger discarding on
|
||||
// platforms where the discard timer is too long (which we'll somewhat
|
||||
// arbitrarily define as 'longer than 60 seconds').
|
||||
var expirationMs =
|
||||
SpecialPowers.getIntPref('image.mem.surfacecache.min_expiration_ms');
|
||||
if (expirationMs > 60000) {
|
||||
ok(true, 'Triggering discarding manually because SurfaceCache expiration ' +
|
||||
'is ' + expirationMs + ' ms');
|
||||
triggerDiscardingManually = true;
|
||||
} else {
|
||||
ok(true, 'Using normal discarding because SurfaceCache expiration ' +
|
||||
'is ' + expirationMs + ' ms');
|
||||
}
|
||||
|
||||
// Enable discarding for the test.
|
||||
SpecialPowers.pushPrefEnv({
|
||||
'set':[['image.mem.discardable',true],
|
||||
['image.mem.min_discard_timeout_ms',1000]]
|
||||
'set':[['image.mem.discardable',true]]
|
||||
}, runTest);
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
// Create the image _after_ setting the discard timer pref
|
||||
var image = new Image();
|
||||
image.setAttribute("id", "gif");
|
||||
image.src = "bug399925.gif";
|
||||
document.getElementById("content").appendChild(image);
|
||||
|
||||
// 1. Draw the canvas once on loadComplete
|
||||
// 2. Redraw the canvas and compare the results right on discard
|
||||
@ -46,6 +56,16 @@ function runTest() {
|
||||
is(pngResults[0], pngResults[1], "got different rendered results");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
image.src = "bug399925.gif";
|
||||
document.getElementById("content").appendChild(image);
|
||||
|
||||
if (triggerDiscardingManually) {
|
||||
var request = SpecialPowers.wrap(image)
|
||||
.QueryInterface(SpecialPowers.Ci.nsIImageLoadingContent)
|
||||
.getRequest(SpecialPowers.Ci.nsIImageLoadingContent.CURRENT_REQUEST);
|
||||
setTimeout(() => request.requestDiscard(), 1000);
|
||||
}
|
||||
}
|
||||
|
||||
function addCallbacks(anImage, loadCompleteCallback, discardCallback) {
|
||||
|
@ -574,7 +574,6 @@ pref("media.fragmented-mp4.android-media-codec.preferred", true);
|
||||
|
||||
// optimize images memory usage
|
||||
pref("image.mem.decodeondraw", true);
|
||||
pref("image.mem.min_discard_timeout_ms", 10000);
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
// Shumway component (SWF player) is disabled by default. Also see bug 904346.
|
||||
|
@ -3775,29 +3775,12 @@ pref("image.mem.decodeondraw", true);
|
||||
// Allows image locking of decoded image data in content processes.
|
||||
pref("image.mem.allow_locking_in_content_processes", true);
|
||||
|
||||
// Minimum timeout for image discarding (in milliseconds). The actual time in
|
||||
// which an image must inactive for it to be discarded will vary between this
|
||||
// value and twice this value.
|
||||
//
|
||||
// This used to be 120 seconds, but having it that high causes our working
|
||||
// set to grow very large. Switching it back to 10 seconds will hopefully
|
||||
// be better.
|
||||
pref("image.mem.min_discard_timeout_ms", 10000);
|
||||
|
||||
// Chunk size for calls to the image decoders
|
||||
pref("image.mem.decode_bytes_at_a_time", 16384);
|
||||
|
||||
// The longest time we can spend in an iteration of an async decode
|
||||
pref("image.mem.max_ms_before_yield", 5);
|
||||
|
||||
// The maximum amount of decoded image data we'll willingly keep around (we
|
||||
// might keep around more than this, but we'll try to get down to this value).
|
||||
pref("image.mem.max_decoded_image_kb", 51200);
|
||||
|
||||
// Hard limit for the amount of decoded image data, 0 means we don't have the
|
||||
// hard limit for it.
|
||||
pref("image.mem.hard_limit_decoded_image_kb", 0);
|
||||
|
||||
// Minimum timeout for expiring unused images from the surface cache, in
|
||||
// milliseconds. This controls how long we store cached temporary surfaces.
|
||||
pref("image.mem.surfacecache.min_expiration_ms", 60000); // 60ms
|
||||
|
Loading…
Reference in New Issue
Block a user