Loading gfx/layers/ImageContainer.cpp +18 −23 Original line number Diff line number Diff line Loading @@ -729,10 +729,11 @@ nsresult PlanarYCbCrImage::BuildSurfaceDescriptorBuffer( // If we can copy directly from the surface, let's do that to avoid the YUV // to RGB conversion. if (mSourceSurface && mSourceSurface->GetSize() == size) { DataSourceSurface::ScopedMap map(mSourceSurface, DataSourceSurface::READ); RefPtr<gfx::DataSourceSurface> sourceSurface = mSourceSurface.Get(); if (sourceSurface && sourceSurface->GetSize() == size) { DataSourceSurface::ScopedMap map(sourceSurface, DataSourceSurface::READ); if (map.IsMapped() && SwizzleData(map.GetData(), map.GetStride(), mSourceSurface->GetFormat(), buffer, sourceSurface->GetFormat(), buffer, stride, format, size)) { return NS_OK; } Loading Loading @@ -906,9 +907,8 @@ nsresult PlanarYCbCrImage::AdoptData(const Data& aData) { } already_AddRefed<gfx::SourceSurface> PlanarYCbCrImage::GetAsSourceSurface() { if (mSourceSurface) { RefPtr<gfx::SourceSurface> surface(mSourceSurface); return surface.forget(); if (RefPtr<gfx::DataSourceSurface> cached = mSourceSurface.Get()) { return cached.forget(); } gfx::IntSize size(mSize); Loading Loading @@ -938,30 +938,24 @@ already_AddRefed<gfx::SourceSurface> PlanarYCbCrImage::GetAsSourceSurface() { return nullptr; } mSourceSurface = surface; mSourceSurface.Set(surface); return surface.forget(); } PlanarYCbCrImage::~PlanarYCbCrImage() { NS_ReleaseOnMainThread("PlanarYCbCrImage::mSourceSurface", mSourceSurface.forget()); } PlanarYCbCrImage::~PlanarYCbCrImage() = default; NVImage::NVImage() : Image(nullptr, ImageFormat::NV_IMAGE), mBufferSize(0) {} NVImage::~NVImage() { NS_ReleaseOnMainThread("NVImage::mSourceSurface", mSourceSurface.forget()); } NVImage::~NVImage() = default; IntSize NVImage::GetSize() const { return mSize; } IntRect NVImage::GetPictureRect() const { return mData.mPictureRect; } already_AddRefed<SourceSurface> NVImage::GetAsSourceSurface() { if (mSourceSurface) { RefPtr<gfx::SourceSurface> surface(mSourceSurface); return surface.forget(); if (RefPtr<gfx::DataSourceSurface> cached = mSourceSurface.Get()) { return cached.forget(); } // Convert the current NV12 or NV21 data to YUV420P so that we can follow the Loading Loading @@ -1020,7 +1014,7 @@ already_AddRefed<SourceSurface> NVImage::GetAsSourceSurface() { return nullptr; } mSourceSurface = surface; mSourceSurface.Set(surface); return surface.forget(); } Loading @@ -1042,7 +1036,8 @@ nsresult NVImage::BuildSurfaceDescriptorBuffer( UniquePtr<uint8_t[]> buffer; if (!mSourceSurface) { RefPtr<gfx::DataSourceSurface> sourceSurface = mSourceSurface.Get(); if (!sourceSurface) { const int bufferLength = ySize.height * mData.mYStride + cbcrSize.height * cbcrSize.width * 2; buffer = MakeUnique<uint8_t[]>(bufferLength); Loading Loading @@ -1072,7 +1067,7 @@ nsresult NVImage::BuildSurfaceDescriptorBuffer( return NS_ERROR_FAILURE; } if (mSourceSurface && mSourceSurface->GetSize() != size) { if (sourceSurface && sourceSurface->GetSize() != size) { return NS_ERROR_NOT_IMPLEMENTED; } Loading @@ -1084,7 +1079,7 @@ nsresult NVImage::BuildSurfaceDescriptorBuffer( return rv; } if (!mSourceSurface) { if (!sourceSurface) { rv = gfx::ConvertYCbCrToRGB(aData, format, size, output, stride); if (NS_WARN_IF(NS_FAILED(rv))) { MOZ_ASSERT_UNREACHABLE("Failed to convert YUV into RGB data"); Loading @@ -1093,12 +1088,12 @@ nsresult NVImage::BuildSurfaceDescriptorBuffer( return NS_OK; } DataSourceSurface::ScopedMap map(mSourceSurface, DataSourceSurface::WRITE); DataSourceSurface::ScopedMap map(sourceSurface, DataSourceSurface::WRITE); if (NS_WARN_IF(!map.IsMapped())) { return NS_ERROR_FAILURE; } if (!SwizzleData(map.GetData(), map.GetStride(), mSourceSurface->GetFormat(), if (!SwizzleData(map.GetData(), map.GetStride(), sourceSurface->GetFormat(), output, stride, format, size)) { return NS_ERROR_FAILURE; } Loading gfx/layers/ImageContainer.h +44 −2 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ #include "ImageTypes.h" // for ImageFormat, etc #include "mozilla/AlreadyAddRefed.h" #include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2 #include "mozilla/DataMutex.h" // for DataMutex #include "mozilla/Mutex.h" // for Mutex #include "mozilla/RecursiveMutex.h" // for RecursiveMutex, etc #include "mozilla/ThreadSafeWeakPtr.h" Loading @@ -26,6 +27,7 @@ #include "nsISupportsImpl.h" // for Image::Release, etc #include "nsTArray.h" // for nsTArray #include "nsThreadUtils.h" // for NS_IsMainThread #include "nsProxyRelease.h" // for NS_ReleaseOnMainThread #include "mozilla/Atomics.h" #include "mozilla/gfx/2D.h" #include "mozilla/EnumeratedArray.h" Loading Loading @@ -205,6 +207,46 @@ class Image { static mozilla::Atomic<int32_t> sSerialCounter; }; /** * A thread-safe, lazily-populated cache of an Image's rasterized surface. */ class CachedSurface final { public: CachedSurface() : mSurface("layers::CachedSurface") {} ~CachedSurface() { // The surface may have been created off the main thread, but like the rest // of the gfx surface machinery it must be released on the main thread. RefPtr<gfx::DataSourceSurface> surface; { auto guard = mSurface.Lock(); surface = guard->forget(); } NS_ReleaseOnMainThread("layers::CachedSurface", surface.forget()); } // Returns the cached surface, or nullptr if nothing has been cached yet. already_AddRefed<gfx::DataSourceSurface> Get() { auto guard = mSurface.Lock(); RefPtr<gfx::DataSourceSurface> surface = *guard; return surface.forget(); } // Stores aSurface unless another thread has already cached one. The caller // may keep using its own surface regardless: both are equivalent // rasterizations of the same image, and keeping the first one avoids dropping // a surface that a concurrent caller may already have handed out. void Set(gfx::DataSourceSurface* aSurface) { auto guard = mSurface.Lock(); if (!*guard) { *guard = aSurface; } } private: mozilla::DataMutex<RefPtr<gfx::DataSourceSurface>> mSurface; }; MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Image::BuildSdbFlags) /** Loading Loading @@ -900,7 +942,7 @@ class PlanarYCbCrImage : public Image { gfx::IntSize mSize; gfx::ColorDepth mColorDepth = gfx::ColorDepth::COLOR_8; gfxImageFormat mOffscreenFormat; RefPtr<gfx::DataSourceSurface> mSourceSurface; CachedSurface mSourceSurface; uint32_t mBufferSize; }; Loading Loading @@ -963,7 +1005,7 @@ class NVImage final : public Image { uint32_t mBufferSize; gfx::IntSize mSize; Data mData; RefPtr<gfx::DataSourceSurface> mSourceSurface; CachedSurface mSourceSurface; }; /** Loading Loading
gfx/layers/ImageContainer.cpp +18 −23 Original line number Diff line number Diff line Loading @@ -729,10 +729,11 @@ nsresult PlanarYCbCrImage::BuildSurfaceDescriptorBuffer( // If we can copy directly from the surface, let's do that to avoid the YUV // to RGB conversion. if (mSourceSurface && mSourceSurface->GetSize() == size) { DataSourceSurface::ScopedMap map(mSourceSurface, DataSourceSurface::READ); RefPtr<gfx::DataSourceSurface> sourceSurface = mSourceSurface.Get(); if (sourceSurface && sourceSurface->GetSize() == size) { DataSourceSurface::ScopedMap map(sourceSurface, DataSourceSurface::READ); if (map.IsMapped() && SwizzleData(map.GetData(), map.GetStride(), mSourceSurface->GetFormat(), buffer, sourceSurface->GetFormat(), buffer, stride, format, size)) { return NS_OK; } Loading Loading @@ -906,9 +907,8 @@ nsresult PlanarYCbCrImage::AdoptData(const Data& aData) { } already_AddRefed<gfx::SourceSurface> PlanarYCbCrImage::GetAsSourceSurface() { if (mSourceSurface) { RefPtr<gfx::SourceSurface> surface(mSourceSurface); return surface.forget(); if (RefPtr<gfx::DataSourceSurface> cached = mSourceSurface.Get()) { return cached.forget(); } gfx::IntSize size(mSize); Loading Loading @@ -938,30 +938,24 @@ already_AddRefed<gfx::SourceSurface> PlanarYCbCrImage::GetAsSourceSurface() { return nullptr; } mSourceSurface = surface; mSourceSurface.Set(surface); return surface.forget(); } PlanarYCbCrImage::~PlanarYCbCrImage() { NS_ReleaseOnMainThread("PlanarYCbCrImage::mSourceSurface", mSourceSurface.forget()); } PlanarYCbCrImage::~PlanarYCbCrImage() = default; NVImage::NVImage() : Image(nullptr, ImageFormat::NV_IMAGE), mBufferSize(0) {} NVImage::~NVImage() { NS_ReleaseOnMainThread("NVImage::mSourceSurface", mSourceSurface.forget()); } NVImage::~NVImage() = default; IntSize NVImage::GetSize() const { return mSize; } IntRect NVImage::GetPictureRect() const { return mData.mPictureRect; } already_AddRefed<SourceSurface> NVImage::GetAsSourceSurface() { if (mSourceSurface) { RefPtr<gfx::SourceSurface> surface(mSourceSurface); return surface.forget(); if (RefPtr<gfx::DataSourceSurface> cached = mSourceSurface.Get()) { return cached.forget(); } // Convert the current NV12 or NV21 data to YUV420P so that we can follow the Loading Loading @@ -1020,7 +1014,7 @@ already_AddRefed<SourceSurface> NVImage::GetAsSourceSurface() { return nullptr; } mSourceSurface = surface; mSourceSurface.Set(surface); return surface.forget(); } Loading @@ -1042,7 +1036,8 @@ nsresult NVImage::BuildSurfaceDescriptorBuffer( UniquePtr<uint8_t[]> buffer; if (!mSourceSurface) { RefPtr<gfx::DataSourceSurface> sourceSurface = mSourceSurface.Get(); if (!sourceSurface) { const int bufferLength = ySize.height * mData.mYStride + cbcrSize.height * cbcrSize.width * 2; buffer = MakeUnique<uint8_t[]>(bufferLength); Loading Loading @@ -1072,7 +1067,7 @@ nsresult NVImage::BuildSurfaceDescriptorBuffer( return NS_ERROR_FAILURE; } if (mSourceSurface && mSourceSurface->GetSize() != size) { if (sourceSurface && sourceSurface->GetSize() != size) { return NS_ERROR_NOT_IMPLEMENTED; } Loading @@ -1084,7 +1079,7 @@ nsresult NVImage::BuildSurfaceDescriptorBuffer( return rv; } if (!mSourceSurface) { if (!sourceSurface) { rv = gfx::ConvertYCbCrToRGB(aData, format, size, output, stride); if (NS_WARN_IF(NS_FAILED(rv))) { MOZ_ASSERT_UNREACHABLE("Failed to convert YUV into RGB data"); Loading @@ -1093,12 +1088,12 @@ nsresult NVImage::BuildSurfaceDescriptorBuffer( return NS_OK; } DataSourceSurface::ScopedMap map(mSourceSurface, DataSourceSurface::WRITE); DataSourceSurface::ScopedMap map(sourceSurface, DataSourceSurface::WRITE); if (NS_WARN_IF(!map.IsMapped())) { return NS_ERROR_FAILURE; } if (!SwizzleData(map.GetData(), map.GetStride(), mSourceSurface->GetFormat(), if (!SwizzleData(map.GetData(), map.GetStride(), sourceSurface->GetFormat(), output, stride, format, size)) { return NS_ERROR_FAILURE; } Loading
gfx/layers/ImageContainer.h +44 −2 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ #include "ImageTypes.h" // for ImageFormat, etc #include "mozilla/AlreadyAddRefed.h" #include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2 #include "mozilla/DataMutex.h" // for DataMutex #include "mozilla/Mutex.h" // for Mutex #include "mozilla/RecursiveMutex.h" // for RecursiveMutex, etc #include "mozilla/ThreadSafeWeakPtr.h" Loading @@ -26,6 +27,7 @@ #include "nsISupportsImpl.h" // for Image::Release, etc #include "nsTArray.h" // for nsTArray #include "nsThreadUtils.h" // for NS_IsMainThread #include "nsProxyRelease.h" // for NS_ReleaseOnMainThread #include "mozilla/Atomics.h" #include "mozilla/gfx/2D.h" #include "mozilla/EnumeratedArray.h" Loading Loading @@ -205,6 +207,46 @@ class Image { static mozilla::Atomic<int32_t> sSerialCounter; }; /** * A thread-safe, lazily-populated cache of an Image's rasterized surface. */ class CachedSurface final { public: CachedSurface() : mSurface("layers::CachedSurface") {} ~CachedSurface() { // The surface may have been created off the main thread, but like the rest // of the gfx surface machinery it must be released on the main thread. RefPtr<gfx::DataSourceSurface> surface; { auto guard = mSurface.Lock(); surface = guard->forget(); } NS_ReleaseOnMainThread("layers::CachedSurface", surface.forget()); } // Returns the cached surface, or nullptr if nothing has been cached yet. already_AddRefed<gfx::DataSourceSurface> Get() { auto guard = mSurface.Lock(); RefPtr<gfx::DataSourceSurface> surface = *guard; return surface.forget(); } // Stores aSurface unless another thread has already cached one. The caller // may keep using its own surface regardless: both are equivalent // rasterizations of the same image, and keeping the first one avoids dropping // a surface that a concurrent caller may already have handed out. void Set(gfx::DataSourceSurface* aSurface) { auto guard = mSurface.Lock(); if (!*guard) { *guard = aSurface; } } private: mozilla::DataMutex<RefPtr<gfx::DataSourceSurface>> mSurface; }; MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Image::BuildSdbFlags) /** Loading Loading @@ -900,7 +942,7 @@ class PlanarYCbCrImage : public Image { gfx::IntSize mSize; gfx::ColorDepth mColorDepth = gfx::ColorDepth::COLOR_8; gfxImageFormat mOffscreenFormat; RefPtr<gfx::DataSourceSurface> mSourceSurface; CachedSurface mSourceSurface; uint32_t mBufferSize; }; Loading Loading @@ -963,7 +1005,7 @@ class NVImage final : public Image { uint32_t mBufferSize; gfx::IntSize mSize; Data mData; RefPtr<gfx::DataSourceSurface> mSourceSurface; CachedSurface mSourceSurface; }; /** Loading