зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1331938 - Part 2. Add SourceSurfaceSharedData, a shared data backed DataSourceSurface. r=nical
This commit is contained in:
Родитель
608d601120
Коммит
cb555a4ef6
|
@ -916,7 +916,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvas
|
|||
aCanvasEl.GetCurrentContextType() == CanvasContextType::WebGL2) &&
|
||||
aCropRect.isSome()) {
|
||||
// The _surface_ must be a DataSourceSurface.
|
||||
MOZ_ASSERT(surface->GetType() == SurfaceType::DATA,
|
||||
MOZ_ASSERT(surface->IsDataSourceSurface(),
|
||||
"The snapshot SourceSurface from WebGL rendering contest is not \
|
||||
DataSourceSurface.");
|
||||
RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
|
||||
|
|
10
gfx/2d/2D.h
10
gfx/2d/2D.h
|
@ -352,6 +352,16 @@ public:
|
|||
*/
|
||||
virtual bool IsValid() const { return true; }
|
||||
|
||||
/**
|
||||
* This function will return true if the surface type matches that of a
|
||||
* DataSourceSurface and if GetDataSurface will return the same object.
|
||||
*/
|
||||
bool IsDataSourceSurface() const {
|
||||
SurfaceType type = GetType();
|
||||
return type == SurfaceType::DATA ||
|
||||
type == SurfaceType::DATA_SHARED;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will get a DataSourceSurface for this surface, a
|
||||
* DataSourceSurface's data can be accessed directly.
|
||||
|
|
|
@ -13,7 +13,7 @@ already_AddRefed<DataSourceSurface>
|
|||
DataSourceSurface::GetDataSurface()
|
||||
{
|
||||
RefPtr<DataSourceSurface> surface =
|
||||
(GetType() == SurfaceType::DATA) ? this : new DataSourceSurfaceWrapper(this);
|
||||
IsDataSourceSurface() ? this : new DataSourceSurfaceWrapper(this);
|
||||
return surface.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -465,6 +465,9 @@ public:
|
|||
case SurfaceType::TILED:
|
||||
mMessage << "SurfaceType::TILED";
|
||||
break;
|
||||
case SurfaceType::DATA_SHARED:
|
||||
mMessage << "SurfaceType::DATA_SHARED";
|
||||
break;
|
||||
default:
|
||||
mMessage << "Invalid SurfaceType (" << (int)aType << ")";
|
||||
break;
|
||||
|
|
|
@ -29,7 +29,8 @@ enum class SurfaceType : int8_t {
|
|||
DUAL_DT, /* Snapshot of a dual drawtarget */
|
||||
D2D1_1_IMAGE, /* A D2D 1.1 ID2D1Image SourceSurface */
|
||||
RECORDING, /* Surface used for recording */
|
||||
TILED /* Surface from a tiled DrawTarget */
|
||||
TILED, /* Surface from a tiled DrawTarget */
|
||||
DATA_SHARED, /* Data surface using shared memory */
|
||||
};
|
||||
|
||||
enum class SurfaceFormat : int8_t {
|
||||
|
|
|
@ -348,6 +348,8 @@ AppendToString(std::stringstream& aStream, gfx::SurfaceType aType,
|
|||
aStream << "SurfaceType::RECORDING"; break;
|
||||
case SurfaceType::TILED:
|
||||
aStream << "SurfaceType::TILED"; break;
|
||||
case SurfaceType::DATA_SHARED:
|
||||
aStream << "SurfaceType::DATA_SHARED"; break;
|
||||
default:
|
||||
NS_ERROR("unknown surface type");
|
||||
aStream << "???";
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "SourceSurfaceSharedData.h"
|
||||
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/Types.h" // for decltype
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
bool
|
||||
SourceSurfaceSharedData::Init(const IntSize &aSize,
|
||||
int32_t aStride,
|
||||
SurfaceFormat aFormat)
|
||||
{
|
||||
mSize = aSize;
|
||||
mStride = aStride;
|
||||
mFormat = aFormat;
|
||||
|
||||
size_t len = GetAlignedDataLength();
|
||||
mBuf = new SharedMemoryBasic();
|
||||
if (NS_WARN_IF(!mBuf->Create(len)) ||
|
||||
NS_WARN_IF(!mBuf->Map(len))) {
|
||||
mBuf = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SourceSurfaceSharedData::GuaranteePersistance()
|
||||
{
|
||||
// Shared memory is not unmapped until we release SourceSurfaceSharedData.
|
||||
}
|
||||
|
||||
void
|
||||
SourceSurfaceSharedData::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
|
||||
size_t& aHeapSizeOut,
|
||||
size_t& aNonHeapSizeOut) const
|
||||
{
|
||||
if (mBuf) {
|
||||
aNonHeapSizeOut += GetAlignedDataLength();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
SourceSurfaceSharedData::GetDataInternal() const
|
||||
{
|
||||
mMutex.AssertCurrentThreadOwns();
|
||||
|
||||
// If we have an old buffer lingering, it is because we get reallocated to
|
||||
// get a new handle to share, but there were still active mappings.
|
||||
if (MOZ_UNLIKELY(mOldBuf)) {
|
||||
MOZ_ASSERT(mMapCount > 0);
|
||||
MOZ_ASSERT(mFinalized);
|
||||
return static_cast<uint8_t*>(mOldBuf->memory());
|
||||
}
|
||||
return static_cast<uint8_t*>(mBuf->memory());
|
||||
}
|
||||
|
||||
nsresult
|
||||
SourceSurfaceSharedData::ShareToProcess(base::ProcessId aPid,
|
||||
SharedMemoryBasic::Handle& aHandle)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
if (mClosed) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
bool shared = mBuf->ShareToProcess(aPid, &aHandle);
|
||||
if (MOZ_UNLIKELY(!shared)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
SourceSurfaceSharedData::CloseHandleInternal()
|
||||
{
|
||||
mMutex.AssertCurrentThreadOwns();
|
||||
|
||||
if (mClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFinalized && mShared) {
|
||||
mBuf->CloseHandle();
|
||||
mClosed = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
SourceSurfaceSharedData::ReallocHandle()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(mClosed);
|
||||
MOZ_ASSERT(mFinalized);
|
||||
|
||||
size_t len = GetAlignedDataLength();
|
||||
RefPtr<SharedMemoryBasic> buf = new SharedMemoryBasic();
|
||||
if (NS_WARN_IF(!buf->Create(len)) ||
|
||||
NS_WARN_IF(!buf->Map(len))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t copyLen = GetDataLength();
|
||||
memcpy(buf->memory(), mBuf->memory(), copyLen);
|
||||
buf->Protect(static_cast<char*>(buf->memory()), len, RightsRead);
|
||||
|
||||
if (mMapCount > 0 && !mOldBuf) {
|
||||
mOldBuf = Move(mBuf);
|
||||
}
|
||||
mBuf = Move(buf);
|
||||
mClosed = false;
|
||||
mShared = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SourceSurfaceSharedData::Finalize()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(!mClosed);
|
||||
MOZ_ASSERT(!mFinalized);
|
||||
|
||||
size_t len = GetAlignedDataLength();
|
||||
mBuf->Protect(static_cast<char*>(mBuf->memory()), len, RightsRead);
|
||||
|
||||
mFinalized = true;
|
||||
CloseHandleInternal();
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,163 @@
|
|||
/* -*- 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;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
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_ */
|
|
@ -201,6 +201,7 @@ EXPORTS.mozilla.layers += [
|
|||
'opengl/TextureHostOGL.h',
|
||||
'PersistentBufferProvider.h',
|
||||
'RenderTrace.h',
|
||||
'SourceSurfaceSharedData.h',
|
||||
'SourceSurfaceVolatileData.h',
|
||||
'TextureWrapperImage.h',
|
||||
'TransactionIdAllocator.h',
|
||||
|
@ -374,6 +375,7 @@ UNIFIED_SOURCES += [
|
|||
'RenderTrace.cpp',
|
||||
'RotatedBuffer.cpp',
|
||||
'ShareableCanvasLayer.cpp',
|
||||
'SourceSurfaceSharedData.cpp',
|
||||
'SourceSurfaceVolatileData.cpp',
|
||||
'TextureWrapperImage.cpp',
|
||||
]
|
||||
|
|
|
@ -885,7 +885,7 @@ gfxUtils::CopySurfaceToDataSourceSurfaceWithFormat(SourceSurface* aSurface,
|
|||
|
||||
Rect bounds(0, 0, aSurface->GetSize().width, aSurface->GetSize().height);
|
||||
|
||||
if (aSurface->GetType() != SurfaceType::DATA) {
|
||||
if (!aSurface->IsDataSourceSurface()) {
|
||||
// If the surface is NOT of type DATA then its data is not mapped into main
|
||||
// memory. Format conversion is probably faster on the GPU, and by doing it
|
||||
// there we can avoid any expensive uploads/readbacks except for (possibly)
|
||||
|
|
|
@ -47,7 +47,7 @@ public:
|
|||
imgIContainer::DECODE_FLAGS_DEFAULT);
|
||||
ASSERT_TRUE(mSurface != nullptr);
|
||||
|
||||
EXPECT_EQ(SurfaceType::DATA, mSurface->GetType());
|
||||
EXPECT_TRUE(mSurface->IsDataSourceSurface());
|
||||
EXPECT_TRUE(mSurface->GetFormat() == SurfaceFormat::B8G8R8X8 ||
|
||||
mSurface->GetFormat() == SurfaceFormat::B8G8R8A8);
|
||||
EXPECT_EQ(mTestCase.mSize, mSurface->GetSize());
|
||||
|
|
|
@ -64,7 +64,7 @@ CheckDecoderState(const ImageTestCase& aTestCase, Decoder* aDecoder)
|
|||
RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
|
||||
|
||||
// Verify that the resulting surfaces matches our expectations.
|
||||
EXPECT_EQ(SurfaceType::DATA, surface->GetType());
|
||||
EXPECT_TRUE(surface->IsDataSourceSurface());
|
||||
EXPECT_TRUE(surface->GetFormat() == SurfaceFormat::B8G8R8X8 ||
|
||||
surface->GetFormat() == SurfaceFormat::B8G8R8A8);
|
||||
EXPECT_EQ(aTestCase.mOutputSize, surface->GetSize());
|
||||
|
|
Загрузка…
Ссылка в новой задаче