author | Seth Fowler <mark.seth.fowler@gmail.com> |
Thu, 04 Jun 2015 11:08:17 -0700 | |
changeset 247182 | e4b22fb2ac017c1a30ffd11cc3d863d0b26d8c7c |
parent 247181 | 89ac61464a450e47d2d6586886fcf486f74c2e9b |
child 247183 | 061363215959d2a92aaa1eb72515c8c80af93844 |
push id | 28855 |
push user | kwierso@gmail.com |
push date | Fri, 05 Jun 2015 01:19:30 +0000 |
treeherder | mozilla-central@227d356ac030 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | tn |
bugs | 1171356 |
milestone | 41.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
b2g/app/b2g.js | file | annotate | diff | comparison | revisions | |
gfx/thebes/gfxPrefs.h | file | annotate | diff | comparison | revisions | |
image/RasterImage.cpp | file | annotate | diff | comparison | revisions | |
image/RasterImage.h | file | annotate | diff | comparison | revisions |
--- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -327,16 +327,17 @@ pref("media.eme.apiVisible", true); // The default number of decoded video frames that are enqueued in // MediaDecoderReader's mVideoQueue. pref("media.video-queue.default-size", 3); // optimize images' memory usage pref("image.downscale-during-decode.enabled", true); pref("image.decode-only-on-draw.enabled", false); pref("image.mem.allow_locking_in_content_processes", true); +pref("image.decode.retry-on-alloc-failure", true); // 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 // about the same as the old 'max_decoded_image_kb'. pref("image.mem.surfacecache.max_size_kb", 131072); // 128MB pref("image.mem.surfacecache.size_factor", 8); // 1/8 of main memory pref("image.mem.surfacecache.discard_factor", 2); // Discard 1/2 of the surface cache at a time. pref("image.mem.surfacecache.min_expiration_ms", 86400000); // 24h, we rely on the out of memory hook
--- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -251,16 +251,17 @@ private: DECL_GFX_PREF(Live, "gl.msaa-level", MSAALevel, uint32_t, 2); DECL_GFX_PREF(Live, "gl.require-hardware", RequireHardwareGL, bool, false); DECL_GFX_PREF(Once, "image.cache.size", ImageCacheSize, int32_t, 5*1024*1024); DECL_GFX_PREF(Once, "image.cache.timeweight", ImageCacheTimeWeight, int32_t, 500); DECL_GFX_PREF(Live, "image.decode-only-on-draw.enabled", ImageDecodeOnlyOnDrawEnabled, bool, true); DECL_GFX_PREF(Live, "image.decode-immediately.enabled", ImageDecodeImmediatelyEnabled, bool, false); + DECL_GFX_PREF(Once, "image.decode.retry-on-alloc-failure", ImageDecodeRetryOnAllocFailure, bool, false); DECL_GFX_PREF(Live, "image.downscale-during-decode.enabled", ImageDownscaleDuringDecodeEnabled, bool, true); DECL_GFX_PREF(Live, "image.high_quality_downscaling.enabled", ImageHQDownscalingEnabled, bool, false); DECL_GFX_PREF(Live, "image.high_quality_downscaling.min_factor", ImageHQDownscalingMinFactor, uint32_t, 1000); DECL_GFX_PREF(Live, "image.high_quality_upscaling.max_size", ImageHQUpscalingMaxSize, uint32_t, 20971520); DECL_GFX_PREF(Once, "image.mem.decode_bytes_at_a_time", ImageMemDecodeBytesAtATime, uint32_t, 200000); DECL_GFX_PREF(Live, "image.mem.discardable", ImageMemDiscardable, bool, false); 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);
--- a/image/RasterImage.cpp +++ b/image/RasterImage.cpp @@ -257,16 +257,17 @@ RasterImage::RasterImage(ImageURL* aURI mDecodeCount(0), mRequestedSampleSize(0), mLastImageContainerDrawResult(DrawResult::NOT_READY), #ifdef DEBUG mFramesNotified(0), #endif mSourceBuffer(new SourceBuffer()), mFrameCount(0), + mRetryCount(0), mHasSize(false), mDecodeOnlyOnDraw(false), mTransient(false), mDiscardable(false), mHasSourceData(false), mHasBeenDecoded(false), mPendingAnimation(false), mAnimationFinished(false), @@ -1337,16 +1338,41 @@ RasterImage::Discard() } bool RasterImage::CanDiscard() { return mHasSourceData && // ...have the source data... !mAnim; // Can never discard animated images } +class RetryDecodeRunnable : public nsRunnable +{ +public: + RetryDecodeRunnable(RasterImage* aImage, + const IntSize& aSize, + uint32_t aFlags) + : mImage(aImage) + , mSize(aSize) + , mFlags(aFlags) + { + MOZ_ASSERT(aImage); + } + + NS_IMETHOD Run() + { + mImage->RequestDecodeForSize(mSize, mFlags); + return NS_OK; + } + +private: + nsRefPtr<RasterImage> mImage; + const IntSize mSize; + const uint32_t mFlags; +}; + // Sets up a decoder for this image. already_AddRefed<Decoder> RasterImage::CreateDecoder(const Maybe<IntSize>& aSize, uint32_t aFlags) { // Make sure we actually get size before doing a full decode. if (aSize) { MOZ_ASSERT(mHasSize, "Must do a size decode before a full decode!"); MOZ_ASSERT(mDownscaleDuringDecode || *aSize == mSize, @@ -1413,16 +1439,43 @@ RasterImage::CreateDecoder(const Maybe<I // need a different type, they need to ask for it themselves. // XXX(seth): Note that we call SetSize() and NeedNewFrame() with the // image's intrinsic size, but AllocateFrame with our target size. decoder->SetSize(mSize, mOrientation); decoder->NeedNewFrame(0, 0, 0, aSize->width, aSize->height, SurfaceFormat::B8G8R8A8); decoder->AllocateFrame(*aSize); } + + if (aSize && decoder->HasError()) { + if (gfxPrefs::ImageDecodeRetryOnAllocFailure() && + mRetryCount < 10) { + // We couldn't allocate the first frame for this image. We're probably in + // a temporary low-memory situation, so fire off a runnable and hope that + // things have improved when it runs. (Unless we've already retried 10 + // times in a row, in which case just give up.) + mRetryCount++; + + if (decoder->ImageIsLocked()) { + UnlockImage(); + } + decoder->TakeProgress(); + decoder->TakeInvalidRect(); + + nsCOMPtr<nsIRunnable> runnable = + new RetryDecodeRunnable(this, *aSize, aFlags); + NS_DispatchToMainThread(runnable); + + return nullptr; + } + } else { + // We didn't encounter an error when allocating the first frame. + mRetryCount = 0; + } + decoder->SetIterator(mSourceBuffer->Iterator()); // Set a target size for downscale-during-decode if applicable. if (mDownscaleDuringDecode && aSize && *aSize != mSize) { DebugOnly<nsresult> rv = decoder->SetTargetSize(*aSize); MOZ_ASSERT(nsresult(rv) != NS_ERROR_NOT_AVAILABLE, "We're downscale-during-decode but decoder doesn't support it?"); MOZ_ASSERT(NS_SUCCEEDED(rv), "Bad downscale-during-decode target size?");
--- a/image/RasterImage.h +++ b/image/RasterImage.h @@ -395,16 +395,19 @@ private: // data #endif // The source data for this image. nsRefPtr<SourceBuffer> mSourceBuffer; // The number of frames this image has. uint32_t mFrameCount; + // The number of times we've retried decoding this image. + uint8_t mRetryCount; + // Boolean flags (clustered together to conserve space): bool mHasSize:1; // Has SetSize() been called? bool mDecodeOnlyOnDraw:1; // Decoding only on draw? bool mTransient:1; // Is the image short-lived? bool mDiscardable:1; // Is container discardable? bool mHasSourceData:1; // Do we have source data? bool mHasBeenDecoded:1; // Decoded at least once? bool mDownscaleDuringDecode:1;