mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-11 16:32:59 +00:00
457e8b9854
Differential Revision: https://phabricator.services.mozilla.com/D23151 --HG-- extra : rebase_source : e71d294805df0d46cf39decd0589b47544a0fffe
196 lines
5.3 KiB
C++
196 lines
5.3 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* 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
|
|
#include "mozilla/layers/SharedSurfacesChild.h"
|
|
|
|
#include "base/process_util.h"
|
|
|
|
#ifdef DEBUG
|
|
/**
|
|
* If defined, this makes SourceSurfaceSharedData::Finalize memory protect the
|
|
* underlying shared buffer in the producing process (the content or UI
|
|
* process). Given flushing the page table is expensive, and its utility is
|
|
* predominantly diagnostic (in case of overrun), turn it off by default.
|
|
*/
|
|
# define SHARED_SURFACE_PROTECT_FINALIZED
|
|
#endif
|
|
|
|
using namespace mozilla::layers;
|
|
|
|
namespace mozilla {
|
|
namespace gfx {
|
|
|
|
bool SourceSurfaceSharedDataWrapper::Init(
|
|
const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat,
|
|
const SharedMemoryBasic::Handle& aHandle, base::ProcessId aCreatorPid) {
|
|
MOZ_ASSERT(!mBuf);
|
|
mSize = aSize;
|
|
mStride = aStride;
|
|
mFormat = aFormat;
|
|
mCreatorPid = aCreatorPid;
|
|
|
|
size_t len = GetAlignedDataLength();
|
|
mBuf = MakeAndAddRef<SharedMemoryBasic>();
|
|
if (NS_WARN_IF(
|
|
!mBuf->SetHandle(aHandle, ipc::SharedMemory::RightsReadOnly)) ||
|
|
NS_WARN_IF(!mBuf->Map(len))) {
|
|
mBuf = nullptr;
|
|
return false;
|
|
}
|
|
|
|
mBuf->CloseHandle();
|
|
return true;
|
|
}
|
|
|
|
void SourceSurfaceSharedDataWrapper::Init(SourceSurfaceSharedData* aSurface) {
|
|
MOZ_ASSERT(!mBuf);
|
|
MOZ_ASSERT(aSurface);
|
|
mSize = aSurface->mSize;
|
|
mStride = aSurface->mStride;
|
|
mFormat = aSurface->mFormat;
|
|
mCreatorPid = base::GetCurrentProcId();
|
|
mBuf = aSurface->mBuf;
|
|
}
|
|
|
|
bool SourceSurfaceSharedData::Init(const IntSize& aSize, int32_t aStride,
|
|
SurfaceFormat aFormat,
|
|
bool aShare /* = true */) {
|
|
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;
|
|
}
|
|
|
|
if (aShare) {
|
|
layers::SharedSurfacesChild::Share(this);
|
|
}
|
|
|
|
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,
|
|
size_t& aExtHandlesOut, uint64_t& aExtIdOut) const {
|
|
MutexAutoLock lock(mMutex);
|
|
if (mBuf) {
|
|
aNonHeapSizeOut += GetAlignedDataLength();
|
|
}
|
|
if (!mClosed) {
|
|
++aExtHandlesOut;
|
|
}
|
|
Maybe<wr::ExternalImageId> extId = SharedSurfacesChild::GetExternalId(this);
|
|
if (extId) {
|
|
aExtIdOut = wr::AsUint64(extId.ref());
|
|
}
|
|
}
|
|
|
|
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);
|
|
MOZ_ASSERT(mHandleCount > 0);
|
|
|
|
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) {
|
|
MOZ_ASSERT(mHandleCount == 0);
|
|
MOZ_ASSERT(mShared);
|
|
return;
|
|
}
|
|
|
|
if (mShared) {
|
|
mBuf->CloseHandle();
|
|
mClosed = true;
|
|
}
|
|
}
|
|
|
|
bool SourceSurfaceSharedData::ReallocHandle() {
|
|
MutexAutoLock lock(mMutex);
|
|
MOZ_ASSERT(mHandleCount > 0);
|
|
MOZ_ASSERT(mClosed);
|
|
|
|
if (NS_WARN_IF(!mFinalized)) {
|
|
// We haven't finished populating the surface data yet, which means we are
|
|
// out of luck, as we have no means of synchronizing with the producer to
|
|
// write new data to a new buffer. This should be fairly rare, caused by a
|
|
// crash in the GPU process, while we were decoding an image.
|
|
return false;
|
|
}
|
|
|
|
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);
|
|
#ifdef SHARED_SURFACE_PROTECT_FINALIZED
|
|
buf->Protect(static_cast<char*>(buf->memory()), len, RightsRead);
|
|
#endif
|
|
|
|
if (mMapCount > 0 && !mOldBuf) {
|
|
mOldBuf = std::move(mBuf);
|
|
}
|
|
mBuf = std::move(buf);
|
|
mClosed = false;
|
|
mShared = false;
|
|
return true;
|
|
}
|
|
|
|
void SourceSurfaceSharedData::Finalize() {
|
|
MutexAutoLock lock(mMutex);
|
|
MOZ_ASSERT(!mFinalized);
|
|
|
|
#ifdef SHARED_SURFACE_PROTECT_FINALIZED
|
|
size_t len = GetAlignedDataLength();
|
|
mBuf->Protect(static_cast<char*>(mBuf->memory()), len, RightsRead);
|
|
#endif
|
|
|
|
mFinalized = true;
|
|
}
|
|
|
|
} // namespace gfx
|
|
} // namespace mozilla
|