gfx/layers/SourceSurfaceSharedData.h
author ffxbld <release@mozilla.com>
Mon, 06 Mar 2017 23:53:55 +0100
changeset 346055 b7e42143bbbc9dc3e5c05bd1e93b6485ce1d0ad4
parent 344583 2c135b467344e72465ccf64f1cd24a18ad28f15d
child 389027 5f74d262924171a8fa0b4483a64f4cac34c4c9b8
child 389102 7e1da430d9f9323ef4fd0690459fd87c8d1ba0ef
permissions -rw-r--r--
Update configs. IGNORE BROKEN CHANGESETS CLOSED TREE NO BUG a=release ba=release MozReview-Commit-ID: GEyM0F1O4hP

/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef MOZILLA_GFX_SOURCESURFACESHAREDDATA_H_
#define MOZILLA_GFX_SOURCESURFACESHAREDDATA_H_

#include "mozilla/gfx/2D.h"
#include "mozilla/Mutex.h"
#include "mozilla/ipc/SharedMemoryBasic.h"

namespace mozilla {
namespace gfx {

/**
 * This class is used to wrap shared (as in process) data buffers used by a
 * source surface.
 */
class SourceSurfaceSharedData final : public DataSourceSurface
{
  typedef mozilla::ipc::SharedMemoryBasic SharedMemoryBasic;

public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceSharedData, override)

  SourceSurfaceSharedData()
    : mMutex("SourceSurfaceSharedData")
    , mStride(0)
    , mMapCount(0)
    , mFormat(SurfaceFormat::UNKNOWN)
    , mClosed(false)
    , mFinalized(false)
    , mShared(false)
  {
  }

  bool Init(const IntSize &aSize,
            int32_t aStride,
            SurfaceFormat aFormat);

  uint8_t* GetData() override
  {
    MutexAutoLock lock(mMutex);
    return GetDataInternal();
  }

  int32_t Stride() override { return mStride; }

  SurfaceType GetType() const override { return SurfaceType::DATA_SHARED; }
  IntSize GetSize() const override { return mSize; }
  SurfaceFormat GetFormat() const override { return mFormat; }

  void GuaranteePersistance() override;

  void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                              size_t& aHeapSizeOut,
                              size_t& aNonHeapSizeOut) const override;

  bool OnHeap() const override
  {
    return false;
  }

  /**
   * Although Map (and Moz2D in general) isn't normally threadsafe,
   * we want to allow it for SourceSurfaceSharedData since it should
   * always be fine (for reading at least).
   *
   * This is the same as the base class implementation except using
   * mMapCount instead of mIsMapped since that breaks for multithread.
   *
   * Additionally if a reallocation happened while there were active
   * mappings, then we guarantee that GetData will continue to return
   * the same data pointer by retaining the old shared buffer until
   * the last mapping is freed via Unmap.
   */
  bool Map(MapType, MappedSurface *aMappedSurface) override
  {
    MutexAutoLock lock(mMutex);
    ++mMapCount;
    aMappedSurface->mData = GetDataInternal();
    aMappedSurface->mStride = mStride;
    return true;
  }

  void Unmap() override
  {
    MutexAutoLock lock(mMutex);
    MOZ_ASSERT(mMapCount > 0);
    if (--mMapCount == 0) {
      mOldBuf = nullptr;
    }
  }

  /**
   * Get a handle to share to another process for this buffer. Returns:
   *   NS_OK -- success, aHandle is valid.
   *   NS_ERROR_NOT_AVAILABLE -- handle was closed, need to reallocate.
   *   NS_ERROR_FAILURE -- failed to create a handle to share.
   */
  nsresult ShareToProcess(base::ProcessId aPid,
                          SharedMemoryBasic::Handle& aHandle);

  /**
   * Indicates the buffer is not expected to be shared with any more processes.
   * May release the handle if possible (see CloseHandleInternal).
   */
  void FinishedSharing()
  {
    MutexAutoLock lock(mMutex);
    mShared = true;
    CloseHandleInternal();
  }

  /**
   * Indicates whether or not the buffer can be shared with another process
   * without reallocating. Note that this is racy and should only be used for
   * informational/reporting purposes.
   */
  bool CanShare() const
  {
    MutexAutoLock lock(mMutex);
    return !mClosed;
  }

  /**
   * Allocate a new shared memory buffer so that we can get a new handle for
   * sharing to new processes. ShareToProcess must have failed with
   * NS_ERROR_NOT_AVAILABLE in order for this to be safe to call. Returns true
   * if the operation succeeds. If it fails, there is no state change.
   */
  bool ReallocHandle();

  /**
   * Indicates we have finished writing to the buffer and it may be marked as
   * read only. May release the handle if possible (see CloseHandleInternal).
   */
  void Finalize();

private:
  ~SourceSurfaceSharedData() override
  {
    MOZ_ASSERT(mMapCount == 0);
  }

  uint8_t* GetDataInternal() const;

  size_t GetDataLength() const
  {
    return static_cast<size_t>(mStride) * mSize.height;
  }

  size_t GetAlignedDataLength() const
  {
    return mozilla::ipc::SharedMemory::PageAlignedSize(GetDataLength());
  }

  /**
   * Attempt to close the handle. Only if the buffer has been both finalized
   * and we have completed sharing will it be released.
   */
  void CloseHandleInternal();

  mutable Mutex mMutex;
  int32_t mStride;
  int32_t mMapCount;
  IntSize mSize;
  RefPtr<SharedMemoryBasic> mBuf;
  RefPtr<SharedMemoryBasic> mOldBuf;
  SurfaceFormat mFormat;
  bool mClosed : 1;
  bool mFinalized : 1;
  bool mShared : 1;
};

} // namespace gfx
} // namespace mozilla

#endif /* MOZILLA_GFX_SOURCESURFACESHAREDDATA_H_ */