Bug 1146663 (Part 1) - Remove HQ scaling, which is now dead code. r=tn

This commit is contained in:
Seth Fowler 2015-09-19 16:20:56 -07:00
parent fa6fe30996
commit 40c407a01f
10 changed files with 30 additions and 341 deletions

View File

@ -62,7 +62,6 @@ pref("browser.cache.memory_limit", 2048); // 2 MB
/* image cache prefs */
pref("image.cache.size", 1048576); // bytes
pref("image.high_quality_downscaling.enabled", false);
pref("canvas.image.cache.limit", 20971520); // 20 MB
/* offline cache prefs */

View File

@ -270,9 +270,6 @@ private:
DECL_GFX_PREF(Once, "image.cache.timeweight", ImageCacheTimeWeight, int32_t, 500);
DECL_GFX_PREF(Live, "image.decode-immediately.enabled", ImageDecodeImmediatelyEnabled, 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(Live, "image.infer-src-animation.threshold-ms", ImageInferSrcAnimationThresholdMS, uint32_t, 2000);
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);

View File

@ -65,142 +65,6 @@ using std::min;
// used for statistics.
static int32_t sMaxDecodeCount = 0;
class ScaleRunner : public nsRunnable
{
enum ScaleState
{
eNew,
eReady,
eFinish,
eFinishWithError
};
public:
ScaleRunner(RasterImage* aImage,
uint32_t aImageFlags,
const IntSize& aSize,
RawAccessFrameRef&& aSrcRef)
: mImage(aImage)
, mSrcRef(Move(aSrcRef))
, mDstSize(aSize)
, mImageFlags(aImageFlags)
, mState(eNew)
{
MOZ_ASSERT(!mSrcRef->GetIsPaletted());
MOZ_ASSERT(aSize.width > 0 && aSize.height > 0);
}
bool Init()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mState == eNew, "Calling Init() twice?");
// We'll need a destination frame. It's unconditionally ARGB32 because
// that's what the scaler outputs.
nsRefPtr<imgFrame> tentativeDstFrame = new imgFrame();
nsresult rv =
tentativeDstFrame->InitForDecoder(mDstSize, SurfaceFormat::B8G8R8A8);
if (NS_FAILED(rv)) {
return false;
}
// We need a strong reference to the raw data for the destination frame.
// (We already got one for the source frame in the constructor.)
RawAccessFrameRef tentativeDstRef = tentativeDstFrame->RawAccessRef();
if (!tentativeDstRef) {
return false;
}
// Everything worked, so commit to these objects and mark ourselves ready.
mDstRef = Move(tentativeDstRef);
mState = eReady;
// Insert the new surface into the cache immediately. We need to do this so
// that we won't start multiple scaling jobs for the same size.
SurfaceCache::Insert(mDstRef.get(), ImageKey(mImage.get()),
RasterSurfaceKey(mDstSize,
ToSurfaceFlags(mImageFlags),
/* aFrameNum = */ 0),
Lifetime::Transient);
return true;
}
NS_IMETHOD Run() override
{
if (mState == eReady) {
// Collect information from the frames that we need to scale.
ScalingData srcData = mSrcRef->GetScalingData();
ScalingData dstData = mDstRef->GetScalingData();
// Actually do the scaling.
bool succeeded =
gfx::Scale(srcData.mRawData, srcData.mSize.width, srcData.mSize.height,
srcData.mBytesPerRow, dstData.mRawData, mDstSize.width,
mDstSize.height, dstData.mBytesPerRow, srcData.mFormat);
if (succeeded) {
// Mark the frame as complete and discardable.
mDstRef->ImageUpdated(mDstRef->GetRect());
MOZ_ASSERT(mDstRef->IsImageComplete(),
"Incomplete, but just updated the entire frame");
}
// We need to send notifications and release our references on the main
// thread, so finish up there.
mState = succeeded ? eFinish : eFinishWithError;
NS_DispatchToMainThread(this);
} else if (mState == eFinish) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mDstRef, "Should have a valid scaled frame");
// Notify, so observers can redraw.
nsRefPtr<RasterImage> image = mImage.get();
if (image) {
image->NotifyNewScaledFrame();
}
// We're done, so release everything.
mSrcRef.reset();
mDstRef.reset();
} else if (mState == eFinishWithError) {
MOZ_ASSERT(NS_IsMainThread());
NS_WARNING("HQ scaling failed");
// Remove the frame from the cache since we know we don't need it.
SurfaceCache::RemoveSurface(ImageKey(mImage.get()),
RasterSurfaceKey(mDstSize,
ToSurfaceFlags(mImageFlags),
/* aFrameNum = */ 0));
// Release everything we're holding, too.
mSrcRef.reset();
mDstRef.reset();
} else {
// mState must be eNew, which is invalid in Run().
MOZ_ASSERT(false, "Need to call Init() before dispatching");
}
return NS_OK;
}
private:
virtual ~ScaleRunner()
{
MOZ_ASSERT(!mSrcRef && !mDstRef,
"Should have released strong refs in Run()");
}
WeakPtr<RasterImage> mImage;
RawAccessFrameRef mSrcRef;
RawAccessFrameRef mDstRef;
const IntSize mDstSize;
uint32_t mImageFlags;
ScaleState mState;
};
static nsCOMPtr<nsIThread> sScaleWorkerThread = nullptr;
#ifndef DEBUG
NS_IMPL_ISUPPORTS(RasterImage, imgIContainer, nsIProperties)
#else
@ -1547,67 +1411,6 @@ RasterImage::RecoverFromInvalidFrames(const IntSize& aSize, uint32_t aFlags)
Decode(aSize, aFlags);
}
bool
RasterImage::CanScale(GraphicsFilter aFilter,
const IntSize& aSize,
uint32_t aFlags)
{
#ifndef MOZ_ENABLE_SKIA
// The high-quality scaler requires Skia.
return false;
#else
// Check basic requirements: HQ downscaling is enabled, we have all the source
// data and know our size, the flags allow us to do it, and a 'good' filter is
// being used. The flags may ask us not to scale because the caller isn't
// drawing to the window. If we're drawing to something else (e.g. a canvas)
// we usually have no way of updating what we've drawn, so HQ scaling is
// useless.
if (!gfxPrefs::ImageHQDownscalingEnabled() || !mHasSize || !mHasSourceData ||
!(aFlags & imgIContainer::FLAG_HIGH_QUALITY_SCALING) ||
aFilter != GraphicsFilter::FILTER_GOOD) {
return false;
}
// We don't HQ scale images that we can downscale during decode.
if (mDownscaleDuringDecode) {
return false;
}
// We don't use the scaler for animated or transient images to avoid doing a
// bunch of work on an image that just gets thrown away.
if (mAnim || mTransient) {
return false;
}
// If target size is 1:1 with original, don't scale.
if (aSize == mSize) {
return false;
}
// To save memory, don't quality upscale images bigger than the limit.
if (aSize.width > mSize.width || aSize.height > mSize.height) {
uint32_t scaledSize = static_cast<uint32_t>(aSize.width * aSize.height);
if (scaledSize > gfxPrefs::ImageHQUpscalingMaxSize()) {
return false;
}
}
// There's no point in scaling if we can't store the result.
if (!SurfaceCache::CanHold(aSize)) {
return false;
}
// XXX(seth): It's not clear what this check buys us over
// gfxPrefs::ImageHQUpscalingMaxSize().
// The default value of this pref is 1000, which means that we never upscale.
// If that's all it's getting us, I'd rather we just forbid that explicitly.
gfx::Size scale(double(aSize.width) / mSize.width,
double(aSize.height) / mSize.height);
gfxFloat minFactor = gfxPrefs::ImageHQDownscalingMinFactor() / 1000.0;
return (scale.width < minFactor || scale.height < minFactor);
#endif
}
bool
RasterImage::CanDownscaleDuringDecode(const IntSize& aSize, uint32_t aFlags)
{
@ -1615,7 +1418,7 @@ RasterImage::CanDownscaleDuringDecode(const IntSize& aSize, uint32_t aFlags)
// image, we have all the source data and know our size, the flags allow us to
// do it, and a 'good' filter is being used.
if (!mDownscaleDuringDecode || !mHasSize ||
!gfxPrefs::ImageHQDownscalingEnabled() ||
!gfxPrefs::ImageDownscaleDuringDecodeEnabled() ||
!(aFlags & imgIContainer::FLAG_HIGH_QUALITY_SCALING)) {
return false;
}
@ -1643,87 +1446,21 @@ RasterImage::CanDownscaleDuringDecode(const IntSize& aSize, uint32_t aFlags)
return true;
}
void
RasterImage::NotifyNewScaledFrame()
{
// Send an invalidation so observers will repaint and can take advantage of
// the new scaled frame if possible.
NotifyProgress(NoProgress, IntRect(0, 0, mSize.width, mSize.height));
}
void
RasterImage::RequestScale(imgFrame* aFrame,
uint32_t aFlags,
const IntSize& aSize)
{
// We don't scale frames which aren't fully decoded.
if (!aFrame->IsImageComplete()) {
return;
}
// We can't scale frames that need padding or are single pixel.
if (aFrame->NeedsPadding() || aFrame->IsSinglePixel()) {
return;
}
// We also can't scale if we can't lock the image data for this frame.
RawAccessFrameRef frameRef = aFrame->RawAccessRef();
if (!frameRef) {
return;
}
nsRefPtr<ScaleRunner> runner =
new ScaleRunner(this, aFlags, aSize, Move(frameRef));
if (runner->Init()) {
if (!sScaleWorkerThread) {
NS_NewNamedThread("Image Scaler", getter_AddRefs(sScaleWorkerThread));
ClearOnShutdown(&sScaleWorkerThread);
}
sScaleWorkerThread->Dispatch(runner, NS_DISPATCH_NORMAL);
}
}
DrawResult
RasterImage::DrawWithPreDownscaleIfNeeded(DrawableFrameRef&& aFrameRef,
gfxContext* aContext,
const IntSize& aSize,
const ImageRegion& aRegion,
GraphicsFilter aFilter,
uint32_t aFlags)
RasterImage::DrawInternal(DrawableFrameRef&& aFrameRef,
gfxContext* aContext,
const IntSize& aSize,
const ImageRegion& aRegion,
GraphicsFilter aFilter,
uint32_t aFlags)
{
DrawableFrameRef frameRef;
if (CanScale(aFilter, aSize, aFlags)) {
LookupResult result =
SurfaceCache::Lookup(ImageKey(this),
RasterSurfaceKey(aSize,
ToSurfaceFlags(aFlags),
/* aFrameNum = */ 0));
if (!result) {
// We either didn't have a matching scaled frame or the OS threw it away.
// Request a new one so we'll be ready next time. For now, we'll fall back
// to aFrameRef below.
RequestScale(aFrameRef.get(), aFlags, aSize);
}
if (result && result.DrawableRef()->IsImageComplete()) {
frameRef = Move(result.DrawableRef()); // The scaled version is ready.
}
}
gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
ImageRegion region(aRegion);
bool frameIsComplete = true; // We already checked HQ scaled frames.
if (!frameRef) {
// There's no HQ scaled frame available, so we'll have to use the frame
// provided by the caller.
frameRef = Move(aFrameRef);
frameIsComplete = frameRef->IsImageComplete();
}
bool frameIsComplete = aFrameRef->IsImageComplete();
// By now we may have a frame with the requested size. If not, we need to
// adjust the drawing parameters accordingly.
IntSize finalSize = frameRef->GetImageSize();
IntSize finalSize = aFrameRef->GetImageSize();
bool couldRedecodeForBetterFrame = false;
if (finalSize != aSize) {
gfx::Size scale(double(aSize.width) / finalSize.width,
@ -1735,7 +1472,7 @@ RasterImage::DrawWithPreDownscaleIfNeeded(DrawableFrameRef&& aFrameRef,
CanDownscaleDuringDecode(aSize, aFlags);
}
if (!frameRef->Draw(aContext, region, aFilter, aFlags)) {
if (!aFrameRef->Draw(aContext, region, aFilter, aFlags)) {
RecoverFromInvalidFrames(aSize, aFlags);
return DrawResult::TEMPORARY_ERROR;
}
@ -1809,8 +1546,8 @@ RasterImage::Draw(gfxContext* aContext,
bool shouldRecordTelemetry = !mDrawStartTime.IsNull() &&
ref->IsImageComplete();
auto result = DrawWithPreDownscaleIfNeeded(Move(ref), aContext, aSize,
aRegion, aFilter, flags);
auto result = DrawInternal(Move(ref), aContext, aSize,
aRegion, aFilter, flags);
if (shouldRecordTelemetry) {
TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime;
@ -2124,28 +1861,9 @@ RasterImage::OptimalImageSizeForDest(const gfxSize& aDest, uint32_t aWhichFrame,
if (aFilter == GraphicsFilter::FILTER_GOOD &&
CanDownscaleDuringDecode(destSize, aFlags)) {
return destSize;
} else if (CanScale(aFilter, destSize, aFlags)) {
LookupResult result =
SurfaceCache::Lookup(ImageKey(this),
RasterSurfaceKey(destSize,
ToSurfaceFlags(aFlags),
/* aFrameNum = */ 0));
if (result && result.DrawableRef()->IsImageComplete()) {
return destSize; // We have an existing HQ scale for this size.
}
if (!result) {
// We could HQ scale to this size, but we haven't. Request a scale now.
DrawableFrameRef ref = LookupFrame(GetRequestedFrameIndex(aWhichFrame),
mSize, aFlags);
if (ref) {
RequestScale(ref.get(), aFlags, destSize);
}
}
}
// We either can't HQ scale to this size or the scaled version isn't ready
// yet. Use our intrinsic size for now.
// We can't scale to this size. Use our intrinsic size for now.
return mSize;
}

View File

@ -254,12 +254,12 @@ public:
private:
nsresult Init(const char* aMimeType, uint32_t aFlags);
DrawResult DrawWithPreDownscaleIfNeeded(DrawableFrameRef&& aFrameRef,
gfxContext* aContext,
const nsIntSize& aSize,
const ImageRegion& aRegion,
GraphicsFilter aFilter,
uint32_t aFlags);
DrawResult DrawInternal(DrawableFrameRef&& aFrameRef,
gfxContext* aContext,
const nsIntSize& aSize,
const ImageRegion& aRegion,
GraphicsFilter aFilter,
uint32_t aFlags);
already_AddRefed<gfx::SourceSurface> CopyFrame(uint32_t aWhichFrame,
uint32_t aFlags);
@ -420,22 +420,10 @@ private: // data
// Scaling.
//////////////////////////////////////////////////////////////////////////////
// Initiates an HQ scale for the given frame, if possible.
void RequestScale(imgFrame* aFrame, uint32_t aFlags, const nsIntSize& aSize);
// Determines whether we can perform an HQ scale with the given parameters.
bool CanScale(GraphicsFilter aFilter, const nsIntSize& aSize,
uint32_t aFlags);
// Determines whether we can downscale during decode with the given
// parameters.
bool CanDownscaleDuringDecode(const nsIntSize& aSize, uint32_t aFlags);
// Called by the HQ scaler when a new scaled frame is ready.
void NotifyNewScaledFrame();
friend class ScaleRunner;
// Error handling.
void DoError();

View File

@ -24,8 +24,8 @@
# behavior than other platforms, and may require "fuzzy-if(winWidget,...)".
# RUN TESTS NOT AFFECTED BY HIGH QUALITY DOWNSCALING:
# ===================================================
# RUN TESTS NOT AFFECTED BY DOWNSCALE-DURING-DECODE:
# ==================================================
== downscale-svg-1a.html downscale-svg-1-ref.html?80
fuzzy(80,468) == downscale-svg-1b.html downscale-svg-1-ref.html?72
== downscale-svg-1c.html downscale-svg-1-ref.html?64
@ -33,9 +33,9 @@ fuzzy(17,208) fuzzy-if(B2G,255,207) == downscale-svg-1d.html downscale-svg-1-ref
fuzzy(78,216) == downscale-svg-1e.html downscale-svg-1-ref.html?40
fuzzy(51,90) == downscale-svg-1f.html downscale-svg-1-ref.html?24
# RUN TESTS WITH HIGH QUALITY DOWNSCALING DISABLED:
# =================================================
default-preferences pref(image.high_quality_downscaling.enabled,false)
# RUN TESTS WITH DOWNSCALE-DURING-DECODE DISABLED:
# ================================================
default-preferences pref(image.downscale-during-decode.enabled,false)
fuzzy-if(winWidget,16,20) fuzzy-if(cocoaWidget,106,31) == downscale-1.html downscale-1-ref.html
@ -90,10 +90,9 @@ fuzzy(20,999) fails-if(OSX>=1008) != downscale-2e.html?205,53,bottom about:blank
== downscale-png.html?16,16,interlaced downscale-png.html?16,16,normal
== downscale-png.html?24,24,interlaced downscale-png.html?24,24,normal
# RUN TESTS WITH HIGH QUALITY DOWNSCALING ENABLED:
# ================================================
# High-quality downscaling enabled:
default-preferences pref(image.high_quality_downscaling.enabled,true)
# RUN TESTS WITH DOWNSCALE-DURING-DECODE ENABLED:
# ===============================================
default-preferences pref(image.downscale-during-decode.enabled,true)
fuzzy(31,127) fuzzy-if(d2d,31,147) == downscale-1.html downscale-1-ref.html # intermittently 147 pixels on win7 accelerated only (not win8)

View File

@ -124,7 +124,7 @@ fails == collapsed-border-top-6.html border-top-10-ref.html
== image-width-left-6.html image-width-6.html
skip pref(image.high_quality_downscaling.enabled,true) == image-high-quality-scaling-1.html image-high-quality-scaling-1-ref.html
skip pref(image.downscale-during-decode.enabled,true) == image-high-quality-scaling-1.html image-high-quality-scaling-1-ref.html
!= offscreen-0-ref.html offscreen-10-ref.html

View File

@ -23,8 +23,8 @@
branch.setBoolPref("extensions.blocklist.enabled", false);
// Make url-classifier updates so rare that they won't affect tests
branch.setIntPref("urlclassifier.updateinterval", 172800);
// Disable high-quality downscaling, since it makes reftests more difficult.
branch.setBoolPref("image.high_quality_downscaling.enabled", false);
// Disable downscale-during-decode, since it makes reftests more difficult.
branch.setBoolPref("image.downscale-during-decode.enabled", false);
// Disable the single-color optimization, since it can cause intermittent
// oranges and it causes many of our tests to test a different code path
// than the one that normal images on the web use.

View File

@ -69,7 +69,6 @@ pref("browser.cache.memory_limit", 5120); // 5 MB
/* image cache prefs */
pref("image.cache.size", 1048576); // bytes
pref("image.high_quality_downscaling.enabled", false);
/* offline cache prefs */
pref("browser.offline-apps.notify", true);

View File

@ -68,7 +68,6 @@ pref("browser.cache.memory_limit", 5120); // 5 MB
/* image cache prefs */
pref("image.cache.size", 1048576); // bytes
pref("image.high_quality_downscaling.enabled", false);
/* offline cache prefs */
pref("browser.offline-apps.notify", true);

View File

@ -4070,16 +4070,6 @@ pref("image.downscale-during-decode.enabled", true);
// The default Accept header sent for images loaded over HTTP(S)
pref("image.http.accept", "image/png,image/*;q=0.8,*/*;q=0.5");
pref("image.high_quality_downscaling.enabled", true);
// The minimum percent downscaling we'll use high-quality downscaling on,
// interpreted as a floating-point number / 1000.
pref("image.high_quality_downscaling.min_factor", 1000);
// The maximum memory size which we'll use high-quality uspcaling on,
// interpreted as number of decoded bytes.
pref("image.high_quality_upscaling.max_size", 20971520);
// The threshold for inferring that changes to an <img> element's |src|
// attribute by JavaScript represent an animation, in milliseconds. If the |src|
// attribute is changing more frequently than this value, then we enter a