Bug 1339202 - Decode images to shared surfaces for WebRender. r=tnikkel
This commit is contained in:
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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>>
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
if (!aIsAnimated && gfxVars::UseWebRender()) {
|
||||||
|
RefPtr<SourceSurfaceSharedData> newSurf = new SourceSurfaceSharedData();
|
||||||
|
if (newSurf->Init(size, stride, format)) {
|
||||||
|
return newSurf.forget();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
RefPtr<SourceSurfaceVolatileData> newSurf= new SourceSurfaceVolatileData();
|
RefPtr<SourceSurfaceVolatileData> newSurf= new SourceSurfaceVolatileData();
|
||||||
if (newSurf->Init(size, stride, format)) {
|
if (newSurf->Init(size, stride, format)) {
|
||||||
return newSurf.forget();
|
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()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user