Verified Commit e17a56a1 authored by Timothy Nikkel's avatar Timothy Nikkel Committed by ma1
Browse files

Bug 2022635. a=pascalc

parent 2d6da74b
Loading
Loading
Loading
Loading
+18 −23
Original line number Diff line number Diff line
@@ -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;
      }
@@ -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);
@@ -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
@@ -1020,7 +1014,7 @@ already_AddRefed<SourceSurface> NVImage::GetAsSourceSurface() {
    return nullptr;
  }

  mSourceSurface = surface;
  mSourceSurface.Set(surface);

  return surface.forget();
}
@@ -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);
@@ -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;
  }

@@ -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");
@@ -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;
  }
+44 −2
Original line number Diff line number Diff line
@@ -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"
@@ -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"
@@ -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)

/**
@@ -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;
};

@@ -963,7 +1005,7 @@ class NVImage final : public Image {
  uint32_t mBufferSize;
  gfx::IntSize mSize;
  Data mData;
  RefPtr<gfx::DataSourceSurface> mSourceSurface;
  CachedSurface mSourceSurface;
};

/**