Bug 980037 - Store scaled images in volatile buffers, r=seth

This commit is contained in:
Michael Wu 2014-03-02 11:17:26 -05:00
parent fd158d8b34
commit cc24631ebc
4 changed files with 59 additions and 35 deletions

View File

@ -249,6 +249,8 @@ public:
bool success = false;
if (dstLocked) {
if (DiscardingEnabled())
dstFrame->SetDiscardable();
success = NS_SUCCEEDED(dstFrame->UnlockImageData());
dstLocked = false;
@ -2563,7 +2565,7 @@ RasterImage::ScalingDone(ScaleRequest* request, ScaleStatus status)
}
}
void
bool
RasterImage::DrawWithPreDownscaleIfNeeded(imgFrame *aFrame,
gfxContext *aContext,
GraphicsFilter aFilter,
@ -2579,8 +2581,9 @@ RasterImage::DrawWithPreDownscaleIfNeeded(imgFrame *aFrame,
imageSpaceToUserSpace.Invert();
gfx::Size scale = ToSize(imageSpaceToUserSpace.ScaleFactors(true));
nsIntRect subimage = aSubimage;
nsRefPtr<gfxASurface> surf;
if (CanScale(aFilter, scale, aFlags)) {
if (CanScale(aFilter, scale, aFlags) && !frame->IsSinglePixel()) {
// If scale factor is still the same that we scaled for and
// ScaleWorker isn't still working, then we can use pre-downscaled frame.
// If scale factor has changed, order new request.
@ -2589,21 +2592,35 @@ RasterImage::DrawWithPreDownscaleIfNeeded(imgFrame *aFrame,
// pre-downscaled frame only for the latest requested scale.
// The solution is to cache more than one scaled image frame
// for each RasterImage.
bool needScaleReq;
if (mScaleResult.status == SCALE_DONE && mScaleResult.scale == scale) {
frame = mScaleResult.frame;
userSpaceToImageSpace.Multiply(gfxMatrix().Scale(scale.width, scale.height));
// Grab and hold the surface to make sure the OS didn't destroy it
mScaleResult.frame->GetSurface(getter_AddRefs(surf));
needScaleReq = !surf;
if (surf) {
frame = mScaleResult.frame;
userSpaceToImageSpace.Multiply(gfxMatrix().Scale(scale.width,
scale.height));
// Since we're switching to a scaled image, we need to transform the
// area of the subimage to draw accordingly, since imgFrame::Draw()
// doesn't know about scaled frames.
subimage.ScaleRoundOut(scale.width, scale.height);
// Since we're switching to a scaled image, we need to transform the
// area of the subimage to draw accordingly, since imgFrame::Draw()
// doesn't know about scaled frames.
subimage.ScaleRoundOut(scale.width, scale.height);
}
} else {
needScaleReq = !(mScaleResult.status == SCALE_PENDING &&
mScaleResult.scale == scale);
}
// If we're not waiting for exactly this result, and there's only one
// instance of this image on this page, ask for a scale.
else if (!(mScaleResult.status == SCALE_PENDING && mScaleResult.scale == scale) &&
mLockCount == 1) {
// If we have an oustanding request, signal it to stop (if it can).
if (needScaleReq && mLockCount == 1) {
if (NS_FAILED(frame->LockImageData())) {
frame->UnlockImageData();
return false;
}
// If we have an outstanding request, signal it to stop (if it can).
if (mScaleRequest) {
mScaleRequest->stopped = true;
}
@ -2617,6 +2634,7 @@ RasterImage::DrawWithPreDownscaleIfNeeded(imgFrame *aFrame,
sScaleWorkerThread->Dispatch(runner, NS_DISPATCH_NORMAL);
}
frame->UnlockImageData();
}
}
@ -2625,8 +2643,8 @@ RasterImage::DrawWithPreDownscaleIfNeeded(imgFrame *aFrame,
mSize.height - framerect.YMost(),
framerect.x);
frame->Draw(aContext, aFilter, userSpaceToImageSpace, aFill, padding, subimage,
aFlags);
return frame->Draw(aContext, aFilter, userSpaceToImageSpace,
aFill, padding, subimage, aFlags);
}
//******************************************************************************
@ -2718,19 +2736,16 @@ RasterImage::Draw(gfxContext *aContext,
return NS_OK; // Getting the frame (above) touches the image and kicks off decoding
}
nsRefPtr<gfxASurface> surf;
if (!frame->IsSinglePixel()) {
frame->GetSurface(getter_AddRefs(surf));
if (!surf) {
// The OS threw out some or all of our buffer. Start decoding again.
ForceDiscard();
WantDecodedFrames();
return NS_OK;
}
bool drawn = DrawWithPreDownscaleIfNeeded(frame, aContext, aFilter,
aUserSpaceToImageSpace, aFill,
aSubimage, aFlags);
if (!drawn) {
// The OS threw out some or all of our buffer. Start decoding again.
ForceDiscard();
WantDecodedFrames();
return NS_OK;
}
DrawWithPreDownscaleIfNeeded(frame, aContext, aFilter, aUserSpaceToImageSpace, aFill, aSubimage, aFlags);
if (mDecoded && !mDrawStartTime.IsNull()) {
TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime;
Telemetry::Accumulate(Telemetry::IMAGE_DECODE_ON_DRAW_LATENCY, int32_t(drawLatency.ToMicroseconds()));

View File

@ -545,7 +545,7 @@ private:
nsresult FinishedSomeDecoding(eShutdownIntent intent = eShutdownIntent_Done,
DecodeRequest* request = nullptr);
void DrawWithPreDownscaleIfNeeded(imgFrame *aFrame,
bool DrawWithPreDownscaleIfNeeded(imgFrame *aFrame,
gfxContext *aContext,
GraphicsFilter aFilter,
const gfxMatrix &aUserSpaceToImageSpace,

View File

@ -419,12 +419,13 @@ imgFrame::SurfaceForDrawing(bool aDoPadding,
gfxRect& aFill,
gfxRect& aSubimage,
gfxRect& aSourceRect,
gfxRect& aImageRect)
gfxRect& aImageRect,
gfxASurface* aSurface)
{
IntSize size(int32_t(aImageRect.Width()), int32_t(aImageRect.Height()));
if (!aDoPadding && !aDoPartialDecode) {
NS_ASSERTION(!mSinglePixel, "This should already have been handled");
return SurfaceWithFormat(new gfxSurfaceDrawable(ThebesSurface(), ThebesIntSize(size)), mFormat);
return SurfaceWithFormat(new gfxSurfaceDrawable(aSurface, ThebesIntSize(size)), mFormat);
}
gfxRect available = gfxRect(mDecoded.x, mDecoded.y, mDecoded.width, mDecoded.height);
@ -445,7 +446,7 @@ imgFrame::SurfaceForDrawing(bool aDoPadding,
if (mSinglePixel) {
tmpCtx.SetDeviceColor(mSinglePixelColor);
} else {
tmpCtx.SetSource(ThebesSurface(), gfxPoint(aPadding.left, aPadding.top));
tmpCtx.SetSource(aSurface, gfxPoint(aPadding.left, aPadding.top));
}
tmpCtx.Rectangle(available);
tmpCtx.Fill();
@ -467,12 +468,11 @@ imgFrame::SurfaceForDrawing(bool aDoPadding,
aImageRect = gfxRect(0, 0, mSize.width, mSize.height);
gfxIntSize availableSize(mDecoded.width, mDecoded.height);
return SurfaceWithFormat(new gfxSurfaceDrawable(ThebesSurface(),
availableSize),
return SurfaceWithFormat(new gfxSurfaceDrawable(aSurface, availableSize),
mFormat);
}
void imgFrame::Draw(gfxContext *aContext, GraphicsFilter aFilter,
bool imgFrame::Draw(gfxContext *aContext, GraphicsFilter aFilter,
const gfxMatrix &aUserSpaceToImageSpace, const gfxRect& aFill,
const nsIntMargin &aPadding, const nsIntRect &aSubimage,
uint32_t aImageFlags)
@ -487,7 +487,7 @@ void imgFrame::Draw(gfxContext *aContext, GraphicsFilter aFilter,
if (mSinglePixel && !doPadding && !doPartialDecode) {
DoSingleColorFastPath(aContext, mSinglePixelColor, aFill);
return;
return true;
}
gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace;
@ -500,12 +500,19 @@ void imgFrame::Draw(gfxContext *aContext, GraphicsFilter aFilter,
NS_ASSERTION(!sourceRect.Intersect(subimage).IsEmpty(),
"We must be allowed to sample *some* source pixels!");
nsRefPtr<gfxASurface> surf;
if (!mSinglePixel) {
surf = ThebesSurface();
if (!surf)
return false;
}
bool doTile = !imageRect.Contains(sourceRect) &&
!(aImageFlags & imgIContainer::FLAG_CLAMP);
SurfaceWithFormat surfaceResult =
SurfaceForDrawing(doPadding, doPartialDecode, doTile, aPadding,
userSpaceToImageSpace, fill, subimage, sourceRect,
imageRect);
imageRect, surf);
if (surfaceResult.IsValid()) {
gfxUtils::DrawPixelSnapped(aContext, surfaceResult.mDrawable,
@ -513,6 +520,7 @@ void imgFrame::Draw(gfxContext *aContext, GraphicsFilter aFilter,
subimage, sourceRect, imageRect, fill,
surfaceResult.mFormat, aFilter, aImageFlags);
}
return true;
}
// This can be called from any thread, but not simultaneously.

View File

@ -49,7 +49,7 @@ public:
nsresult Init(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, gfxImageFormat aFormat, uint8_t aPaletteDepth = 0);
nsresult Optimize();
void Draw(gfxContext *aContext, GraphicsFilter aFilter,
bool Draw(gfxContext *aContext, GraphicsFilter aFilter,
const gfxMatrix &aUserSpaceToImageSpace, const gfxRect& aFill,
const nsIntMargin &aPadding, const nsIntRect &aSubimage,
uint32_t aImageFlags = imgIContainer::FLAG_NONE);
@ -182,7 +182,8 @@ private: // methods
gfxRect& aFill,
gfxRect& aSubimage,
gfxRect& aSourceRect,
gfxRect& aImageRect);
gfxRect& aImageRect,
gfxASurface* aSurface);
private: // data
nsRefPtr<gfxImageSurface> mImageSurface;