Bug 1339202 - Decode images to shared surfaces for WebRender. r=tnikkel

This commit is contained in:
Andrew Osmond
2017-02-08 15:48:59 -05:00
parent 38091e3d4f
commit c03ed5beaf
7 changed files with 98 additions and 10 deletions

View File

@@ -64,6 +64,7 @@ Decoder::Decoder(RasterImage* aImage)
, mDecodeDone(false) , mDecodeDone(false)
, mError(false) , mError(false)
, mShouldReportError(false) , mShouldReportError(false)
, mFinalizeFrames(true)
{ } { }
Decoder::~Decoder() Decoder::~Decoder()
@@ -455,7 +456,7 @@ Decoder::PostFrameStop(Opacity aFrameOpacity
mFinishedNewFrame = true; mFinishedNewFrame = true;
mCurrentFrame->Finish(aFrameOpacity, aDisposalMethod, aTimeout, mCurrentFrame->Finish(aFrameOpacity, aDisposalMethod, aTimeout,
aBlendMethod, aBlendRect); aBlendMethod, aBlendRect, mFinalizeFrames);
mProgress |= FLAG_FRAME_COMPLETE; mProgress |= FLAG_FRAME_COMPLETE;

View File

@@ -262,6 +262,10 @@ public:
bool HasError() const { return mError; } bool HasError() const { return mError; }
bool ShouldReportError() const { return mShouldReportError; } bool ShouldReportError() const { return mShouldReportError; }
// Finalize frames
void SetFinalizeFrames(bool aFinalize) { mFinalizeFrames = aFinalize; }
bool GetFinalizeFrames() const { return mFinalizeFrames; }
/// Did we finish decoding enough that calling Decode() again would be useless? /// Did we finish decoding enough that calling Decode() again would be useless?
bool GetDecodeDone() const bool GetDecodeDone() const
{ {
@@ -546,6 +550,7 @@ private:
bool mDecodeDone : 1; bool mDecodeDone : 1;
bool mError : 1; bool mError : 1;
bool mShouldReportError : 1; bool mShouldReportError : 1;
bool mFinalizeFrames : 1;
}; };
} // namespace image } // namespace image

View File

@@ -266,6 +266,7 @@ DecoderFactory::CreateDecoderForICOResource(DecoderType aType,
decoder->SetOutputSize(aICODecoder->OutputSize()); decoder->SetOutputSize(aICODecoder->OutputSize());
decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags()); decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags());
decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags()); decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags());
decoder->SetFinalizeFrames(false);
if (NS_FAILED(decoder->Init())) { if (NS_FAILED(decoder->Init())) {
return nullptr; return nullptr;

View File

@@ -479,7 +479,7 @@ NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
RasterImage::GetFrame(uint32_t aWhichFrame, RasterImage::GetFrame(uint32_t aWhichFrame,
uint32_t aFlags) uint32_t aFlags)
{ {
return GetFrameInternal(mSize, aWhichFrame, aFlags).second().forget(); return GetFrameAtSize(mSize, aWhichFrame, aFlags);
} }
NS_IMETHODIMP_(already_AddRefed<SourceSurface>) NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
@@ -487,7 +487,12 @@ RasterImage::GetFrameAtSize(const IntSize& aSize,
uint32_t aWhichFrame, uint32_t aWhichFrame,
uint32_t aFlags) uint32_t aFlags)
{ {
return GetFrameInternal(aSize, aWhichFrame, aFlags).second().forget(); RefPtr<SourceSurface> surf =
GetFrameInternal(aSize, aWhichFrame, aFlags).second().forget();
// If we are here, it suggests the image is embedded in a canvas or some
// other path besides layers, and we won't need the file handle.
MarkSurfaceShared(surf);
return surf.forget();
} }
Pair<DrawResult, RefPtr<SourceSurface>> Pair<DrawResult, RefPtr<SourceSurface>>

View File

@@ -593,6 +593,13 @@ nsICODecoder::FinishResource()
return Transition::TerminateFailure(); return Transition::TerminateFailure();
} }
// Finalize the frame which we deferred to ensure we could modify the final
// result (e.g. to apply the BMP mask).
MOZ_ASSERT(!mContainedDecoder->GetFinalizeFrames());
if (mCurrentFrame) {
mCurrentFrame->FinalizeSurface();
}
return Transition::TerminateSuccess(); return Transition::TerminateSuccess();
} }

View File

@@ -12,7 +12,6 @@
#include "gfx2DGlue.h" #include "gfx2DGlue.h"
#include "gfxPlatform.h" #include "gfxPlatform.h"
#include "gfxPrefs.h"
#include "gfxUtils.h" #include "gfxUtils.h"
#include "gfxAlphaRecovery.h" #include "gfxAlphaRecovery.h"
@@ -20,6 +19,8 @@
#include "MainThreadUtils.h" #include "MainThreadUtils.h"
#include "mozilla/CheckedInt.h" #include "mozilla/CheckedInt.h"
#include "mozilla/gfx/Tools.h" #include "mozilla/gfx/Tools.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/layers/SourceSurfaceSharedData.h"
#include "mozilla/layers/SourceSurfaceVolatileData.h" #include "mozilla/layers/SourceSurfaceVolatileData.h"
#include "mozilla/Likely.h" #include "mozilla/Likely.h"
#include "mozilla/MemoryReporting.h" #include "mozilla/MemoryReporting.h"
@@ -51,6 +52,12 @@ CreateLockedSurface(DataSourceSurface *aSurface,
const IntSize& size, const IntSize& size,
SurfaceFormat format) SurfaceFormat format)
{ {
// Shared memory is never released until the surface itself is released
if (aSurface->GetType() == SurfaceType::DATA_SHARED) {
RefPtr<DataSourceSurface> surf(aSurface);
return surf.forget();
}
DataSourceSurface::ScopedMap* smap = DataSourceSurface::ScopedMap* smap =
new DataSourceSurface::ScopedMap(aSurface, DataSourceSurface::READ_WRITE); new DataSourceSurface::ScopedMap(aSurface, DataSourceSurface::READ_WRITE);
if (smap->IsMapped()) { if (smap->IsMapped()) {
@@ -77,11 +84,17 @@ AllocateBufferForImage(const IntSize& size,
bool aIsAnimated = false) bool aIsAnimated = false)
{ {
int32_t stride = VolatileSurfaceStride(size, format); int32_t stride = VolatileSurfaceStride(size, format);
RefPtr<SourceSurfaceVolatileData> newSurf = new SourceSurfaceVolatileData(); if (!aIsAnimated && gfxVars::UseWebRender()) {
RefPtr<SourceSurfaceSharedData> newSurf = new SourceSurfaceSharedData();
if (newSurf->Init(size, stride, format)) { if (newSurf->Init(size, stride, format)) {
return newSurf.forget(); return newSurf.forget();
} }
} else {
RefPtr<SourceSurfaceVolatileData> newSurf= new SourceSurfaceVolatileData();
if (newSurf->Init(size, stride, format)) {
return newSurf.forget();
}
}
return nullptr; return nullptr;
} }
@@ -108,6 +121,19 @@ ClearSurface(DataSourceSurface* aSurface, const IntSize& aSize, SurfaceFormat aF
return true; return true;
} }
void
MarkSurfaceShared(SourceSurface* aSurface)
{
// Depending on what requested the image decoding, the buffer may or may not
// end up being shared with another process (e.g. put in a painted layer,
// used inside a canvas). If not shared, we should ensure are not keeping the
// handle only because we have yet to share it.
if (aSurface && aSurface->GetType() == SurfaceType::DATA_SHARED) {
auto sharedSurface = static_cast<SourceSurfaceSharedData*>(aSurface);
sharedSurface->FinishedSharing();
}
}
// Returns true if an image of aWidth x aHeight is allowed and legal. // Returns true if an image of aWidth x aHeight is allowed and legal.
static bool static bool
AllowedImageSize(int32_t aWidth, int32_t aHeight) AllowedImageSize(int32_t aWidth, int32_t aHeight)
@@ -359,6 +385,8 @@ imgFrame::InitWithDrawable(gfxDrawable* aDrawable,
// We used an offscreen surface, which is an "optimized" surface from // We used an offscreen surface, which is an "optimized" surface from
// imgFrame's perspective. // imgFrame's perspective.
mOptSurface = target->Snapshot(); mOptSurface = target->Snapshot();
} else {
FinalizeSurface();
} }
// If we reach this point, we should regard ourselves as complete. // If we reach this point, we should regard ourselves as complete.
@@ -551,6 +579,10 @@ bool imgFrame::Draw(gfxContext* aContext, const ImageRegion& aRegion,
imageRect.Size(), region, surfaceResult.mFormat, imageRect.Size(), region, surfaceResult.mFormat,
aSamplingFilter, aImageFlags, aOpacity); aSamplingFilter, aImageFlags, aOpacity);
} }
// Image got put into a painted layer, it will not be shared with another
// process.
MarkSurfaceShared(surf);
return true; return true;
} }
@@ -581,7 +613,8 @@ imgFrame::Finish(Opacity aFrameOpacity /* = Opacity::SOME_TRANSPARENCY */,
FrameTimeout aTimeout FrameTimeout aTimeout
/* = FrameTimeout::FromRawMilliseconds(0) */, /* = FrameTimeout::FromRawMilliseconds(0) */,
BlendMethod aBlendMethod /* = BlendMethod::OVER */, BlendMethod aBlendMethod /* = BlendMethod::OVER */,
const Maybe<IntRect>& aBlendRect /* = Nothing() */) const Maybe<IntRect>& aBlendRect /* = Nothing() */,
bool aFinalize /* = true */)
{ {
MonitorAutoLock lock(mMonitor); MonitorAutoLock lock(mMonitor);
MOZ_ASSERT(mLockCount > 0, "Image data should be locked"); MOZ_ASSERT(mLockCount > 0, "Image data should be locked");
@@ -591,6 +624,11 @@ imgFrame::Finish(Opacity aFrameOpacity /* = Opacity::SOME_TRANSPARENCY */,
mBlendMethod = aBlendMethod; mBlendMethod = aBlendMethod;
mBlendRect = aBlendRect; mBlendRect = aBlendRect;
ImageUpdatedInternal(GetRect()); ImageUpdatedInternal(GetRect());
if (aFinalize) {
FinalizeSurfaceInternal();
}
mFinished = true; mFinished = true;
// The image is now complete, wake up anyone who's waiting. // The image is now complete, wake up anyone who's waiting.
@@ -633,6 +671,9 @@ imgFrame::GetImageDataInternal(uint8_t** aData, uint32_t* aLength) const
MOZ_ASSERT(mLockCount > 0, "Image data should be locked"); MOZ_ASSERT(mLockCount > 0, "Image data should be locked");
if (mLockedSurface) { if (mLockedSurface) {
// TODO: This is okay for now because we only realloc shared surfaces on
// the main thread after decoding has finished, but if animations want to
// read frame data off the main thread, we will need to reconsider this.
*aData = mLockedSurface->GetData(); *aData = mLockedSurface->GetData();
MOZ_ASSERT(*aData, MOZ_ASSERT(*aData,
"mLockedSurface is non-null, but GetData is null in GetImageData"); "mLockedSurface is non-null, but GetData is null in GetImageData");
@@ -753,6 +794,27 @@ imgFrame::SetOptimizable()
mOptimizable = true; mOptimizable = true;
} }
void
imgFrame::FinalizeSurface()
{
MonitorAutoLock lock(mMonitor);
FinalizeSurfaceInternal();
}
void
imgFrame::FinalizeSurfaceInternal()
{
mMonitor.AssertCurrentThreadOwns();
// Not all images will have mRawSurface to finalize (i.e. paletted images).
if (!mRawSurface || mRawSurface->GetType() != SurfaceType::DATA_SHARED) {
return;
}
auto sharedSurf = static_cast<SourceSurfaceSharedData*>(mRawSurface.get());
sharedSurf->Finalize();
}
already_AddRefed<SourceSurface> already_AddRefed<SourceSurface>
imgFrame::GetSourceSurface() imgFrame::GetSourceSurface()
{ {

View File

@@ -279,12 +279,15 @@ public:
* @param aBlendRect For animation frames, if present, the subrect in * @param aBlendRect For animation frames, if present, the subrect in
* which @aBlendMethod applies. Outside of this * which @aBlendMethod applies. Outside of this
* subrect, BlendMethod::OVER is always used. * subrect, BlendMethod::OVER is always used.
* @param aFinalize Finalize the underlying surface (e.g. so that it
* may be marked as read only if possible).
*/ */
void Finish(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY, void Finish(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
DisposalMethod aDisposalMethod = DisposalMethod::KEEP, DisposalMethod aDisposalMethod = DisposalMethod::KEEP,
FrameTimeout aTimeout = FrameTimeout::FromRawMilliseconds(0), FrameTimeout aTimeout = FrameTimeout::FromRawMilliseconds(0),
BlendMethod aBlendMethod = BlendMethod::OVER, BlendMethod aBlendMethod = BlendMethod::OVER,
const Maybe<IntRect>& aBlendRect = Nothing()); const Maybe<IntRect>& aBlendRect = Nothing(),
bool aFinalize = true);
/** /**
* Mark this imgFrame as aborted. This informs the imgFrame that if it isn't * Mark this imgFrame as aborted. This informs the imgFrame that if it isn't
@@ -341,6 +344,7 @@ public:
void SetOptimizable(); void SetOptimizable();
void FinalizeSurface();
already_AddRefed<SourceSurface> GetSourceSurface(); already_AddRefed<SourceSurface> GetSourceSurface();
void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut, void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut,
@@ -361,6 +365,7 @@ private: // methods
void GetImageDataInternal(uint8_t** aData, uint32_t* length) const; void GetImageDataInternal(uint8_t** aData, uint32_t* length) const;
uint32_t GetImageBytesPerRow() const; uint32_t GetImageBytesPerRow() const;
uint32_t GetImageDataLength() const; uint32_t GetImageDataLength() const;
void FinalizeSurfaceInternal();
already_AddRefed<SourceSurface> GetSourceSurfaceInternal(); already_AddRefed<SourceSurface> GetSourceSurfaceInternal();
uint32_t PaletteDataLength() const uint32_t PaletteDataLength() const
@@ -617,6 +622,8 @@ private:
RefPtr<imgFrame> mFrame; RefPtr<imgFrame> mFrame;
}; };
void MarkSurfaceShared(gfx::SourceSurface* aSurface);
} // namespace image } // namespace image
} // namespace mozilla } // namespace mozilla