Bug 1741767: Use shared memory surfaces in Canvas 2D recording. r=lsalzman

This also changes SharedSurfacesParent to use a StaticMonitor, so that we can
wait for the surface to be added.

Differential Revision: https://phabricator.services.mozilla.com/D132703
This commit is contained in:
Bob Owen 2022-01-15 05:17:21 +00:00
parent 8108a5c646
commit 0abafd6d24
8 changed files with 79 additions and 34 deletions

View File

@ -8,6 +8,7 @@
#include <string.h>
#include "mozilla/layers/SharedSurfacesChild.h"
#include "nsThreadUtils.h"
namespace mozilla {
@ -501,6 +502,18 @@ void CanvasEventRingBuffer::ReturnRead(char* aOut, size_t aSize) {
mWrite->returnCount = readCount;
}
void CanvasDrawEventRecorder::StoreSourceSurfaceRecording(
gfx::SourceSurface* aSurface, const char* aReason) {
wr::ExternalImageId extId{};
nsresult rv = layers::SharedSurfacesChild::Share(aSurface, extId);
if (NS_FAILED(rv)) {
DrawEventRecorderPrivate::StoreSourceSurfaceRecording(aSurface, aReason);
return;
}
StoreExternalSurfaceRecording(aSurface, wr::AsUint64(extId));
}
void CanvasDrawEventRecorder::RecordSourceSurfaceDestruction(void* aSurface) {
// We must only record things on the main thread and surfaces that have been
// recorded can sometimes be destroyed off the main thread.

View File

@ -253,6 +253,9 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate {
aEvent.RecordToStream(mOutputStream);
}
void StoreSourceSurfaceRecording(gfx::SourceSurface* aSurface,
const char* aReason) final;
void RecordSourceSurfaceDestruction(void* aSurface) final;
void Flush() final {}

View File

@ -200,6 +200,13 @@ void CanvasChild::OnTextureForwarded() {
mHasOutstandingWriteLock = false;
}
// We hold onto the last transaction's external surfaces until we have waited
// for the write locks in this transaction. This means we know that the
// surfaces have been picked up in the canvas threads and there is no race
// with them being removed from SharedSurfacesParent. Note this releases the
// current contents of mLastTransactionExternalSurfaces.
mRecorder->TakeExternalSurfaces(mLastTransactionExternalSurfaces);
}
void CanvasChild::EnsureBeginTransaction() {

View File

@ -141,6 +141,7 @@ class CanvasChild final : public PCanvasChild {
uint32_t mLastWriteLockCheckpoint = 0;
uint32_t mTransactionsSinceGetDataSurface = kCacheDataSurfaceThreshold;
TimeStamp mLastNonEmptyTransaction = TimeStamp::NowLoRes();
std::vector<RefPtr<gfx::SourceSurface>> mLastTransactionExternalSurfaces;
bool mIsInTransaction = false;
bool mHasOutstandingWriteLock = false;
};

View File

@ -11,6 +11,7 @@
#include "mozilla/gfx/GPUParent.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/layers/SharedSurfacesParent.h"
#include "mozilla/layers/TextureClient.h"
#include "mozilla/SyncRunnable.h"
#include "mozilla/Telemetry.h"
@ -502,6 +503,11 @@ UniquePtr<SurfaceDescriptor> CanvasTranslator::WaitForSurfaceDescriptor(
return descriptor;
}
already_AddRefed<gfx::SourceSurface> CanvasTranslator::LookupExternalSurface(
uint64_t aKey) {
return SharedSurfacesParent::Get(wr::ToExternalImageId(aKey));
}
already_AddRefed<gfx::GradientStops> CanvasTranslator::GetOrCreateGradientStops(
gfx::GradientStop* aRawStops, uint32_t aNumStops,
gfx::ExtendMode aExtendMode) {

View File

@ -175,6 +175,9 @@ class CanvasTranslator final : public gfx::InlineTranslator,
InlineTranslator::RemoveSourceSurface(aRefPtr);
}
already_AddRefed<gfx::SourceSurface> LookupExternalSurface(
uint64_t aKey) final;
/**
* Gets the cached DataSourceSurface, if it exists, associated with a
* SourceSurface from another process.

View File

@ -22,26 +22,30 @@ namespace layers {
using namespace mozilla::gfx;
StaticMutex SharedSurfacesParent::sMutex;
StaticMonitor SharedSurfacesParent::sMonitor;
StaticAutoPtr<SharedSurfacesParent> SharedSurfacesParent::sInstance;
// Short wait to allow for a surface to be added, where the consumer has a
// different thread route.
static const TimeDuration kGetTimeout = TimeDuration::FromMilliseconds(50);
void SharedSurfacesParent::MappingTracker::NotifyExpiredLocked(
SourceSurfaceSharedDataWrapper* aSurface,
const StaticMutexAutoLock& aAutoLock) {
const StaticMonitorAutoLock& aAutoLock) {
RemoveObjectLocked(aSurface, aAutoLock);
mExpired.AppendElement(aSurface);
}
void SharedSurfacesParent::MappingTracker::TakeExpired(
nsTArray<RefPtr<gfx::SourceSurfaceSharedDataWrapper>>& aExpired,
const StaticMutexAutoLock& aAutoLock) {
const StaticMonitorAutoLock& aAutoLock) {
aExpired = std::move(mExpired);
}
void SharedSurfacesParent::MappingTracker::NotifyHandlerEnd() {
nsTArray<RefPtr<gfx::SourceSurfaceSharedDataWrapper>> expired;
{
StaticMutexAutoLock lock(sMutex);
StaticMonitorAutoLock lock(sMonitor);
TakeExpired(expired, lock);
}
@ -56,7 +60,7 @@ SharedSurfacesParent::SharedSurfacesParent()
/* static */
void SharedSurfacesParent::Initialize() {
MOZ_ASSERT(NS_IsMainThread());
StaticMutexAutoLock lock(sMutex);
StaticMonitorAutoLock lock(sMonitor);
if (!sInstance) {
sInstance = new SharedSurfacesParent();
}
@ -67,7 +71,7 @@ void SharedSurfacesParent::ShutdownRenderThread() {
// The main thread should blocked on waiting for the render thread to
// complete so this should be safe to release off the main thread.
MOZ_ASSERT(wr::RenderThread::IsInRenderThread());
StaticMutexAutoLock lock(sMutex);
StaticMonitorAutoLock lock(sMonitor);
MOZ_ASSERT(sInstance);
for (const auto& key : sInstance->mSurfaces.Keys()) {
@ -85,28 +89,34 @@ void SharedSurfacesParent::Shutdown() {
// thread that could use it. The expiration tracker needs to be freed on the
// main thread.
MOZ_ASSERT(NS_IsMainThread());
StaticMutexAutoLock lock(sMutex);
StaticMonitorAutoLock lock(sMonitor);
sInstance = nullptr;
}
/* static */
already_AddRefed<DataSourceSurface> SharedSurfacesParent::Get(
const wr::ExternalImageId& aId) {
StaticMutexAutoLock lock(sMutex);
StaticMonitorAutoLock lock(sMonitor);
if (!sInstance) {
gfxCriticalNote << "SSP:Get " << wr::AsUint64(aId) << " shtd";
return nullptr;
}
RefPtr<SourceSurfaceSharedDataWrapper> surface;
sInstance->mSurfaces.Get(wr::AsUint64(aId), getter_AddRefs(surface));
while (
!sInstance->mSurfaces.Get(wr::AsUint64(aId), getter_AddRefs(surface))) {
CVStatus status = lock.Wait(kGetTimeout);
if (status == CVStatus::Timeout) {
return nullptr;
}
}
return surface.forget();
}
/* static */
already_AddRefed<DataSourceSurface> SharedSurfacesParent::Acquire(
const wr::ExternalImageId& aId) {
StaticMutexAutoLock lock(sMutex);
StaticMonitorAutoLock lock(sMonitor);
if (!sInstance) {
gfxCriticalNote << "SSP:Acq " << wr::AsUint64(aId) << " shtd";
return nullptr;
@ -125,7 +135,7 @@ already_AddRefed<DataSourceSurface> SharedSurfacesParent::Acquire(
/* static */
bool SharedSurfacesParent::Release(const wr::ExternalImageId& aId,
bool aForCreator) {
StaticMutexAutoLock lock(sMutex);
StaticMonitorAutoLock lock(sMonitor);
if (!sInstance) {
return false;
}
@ -151,7 +161,7 @@ void SharedSurfacesParent::AddSameProcess(const wr::ExternalImageId& aId,
SourceSurfaceSharedData* aSurface) {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(NS_IsMainThread());
StaticMutexAutoLock lock(sMutex);
StaticMonitorAutoLock lock(sMonitor);
if (!sInstance) {
gfxCriticalNote << "SSP:Ads " << wr::AsUint64(aId) << " shtd";
return;
@ -174,11 +184,12 @@ void SharedSurfacesParent::AddSameProcess(const wr::ExternalImageId& aId,
surface->AddConsumer();
sInstance->mSurfaces.InsertOrUpdate(id, std::move(surface));
lock.NotifyAll();
}
/* static */
void SharedSurfacesParent::DestroyProcess(base::ProcessId aPid) {
StaticMutexAutoLock lock(sMutex);
StaticMonitorAutoLock lock(sMonitor);
if (!sInstance) {
return;
}
@ -217,7 +228,7 @@ void SharedSurfacesParent::Add(const wr::ExternalImageId& aId,
surface->Init(aDesc.size(), aDesc.stride(), aDesc.format(),
std::move(aDesc.handle()), aPid);
StaticMutexAutoLock lock(sMutex);
StaticMonitorAutoLock lock(sMonitor);
if (!sInstance) {
gfxCriticalNote << "SSP:Add " << wr::AsUint64(aId) << " shtd";
return;
@ -231,6 +242,7 @@ void SharedSurfacesParent::Add(const wr::ExternalImageId& aId,
surface->AddConsumer();
sInstance->mSurfaces.InsertOrUpdate(id, std::move(surface));
lock.NotifyAll();
}
/* static */
@ -242,7 +254,7 @@ void SharedSurfacesParent::Remove(const wr::ExternalImageId& aId) {
/* static */
void SharedSurfacesParent::AddTrackingLocked(
SourceSurfaceSharedDataWrapper* aSurface,
const StaticMutexAutoLock& aAutoLock) {
const StaticMonitorAutoLock& aAutoLock) {
MOZ_ASSERT(!aSurface->GetExpirationState()->IsTracked());
sInstance->mTracker.AddObjectLocked(aSurface, aAutoLock);
}
@ -250,7 +262,7 @@ void SharedSurfacesParent::AddTrackingLocked(
/* static */
void SharedSurfacesParent::AddTracking(
SourceSurfaceSharedDataWrapper* aSurface) {
StaticMutexAutoLock lock(sMutex);
StaticMonitorAutoLock lock(sMonitor);
if (!sInstance) {
return;
}
@ -261,7 +273,7 @@ void SharedSurfacesParent::AddTracking(
/* static */
void SharedSurfacesParent::RemoveTrackingLocked(
SourceSurfaceSharedDataWrapper* aSurface,
const StaticMutexAutoLock& aAutoLock) {
const StaticMonitorAutoLock& aAutoLock) {
if (!aSurface->GetExpirationState()->IsTracked()) {
return;
}
@ -272,7 +284,7 @@ void SharedSurfacesParent::RemoveTrackingLocked(
/* static */
void SharedSurfacesParent::RemoveTracking(
SourceSurfaceSharedDataWrapper* aSurface) {
StaticMutexAutoLock lock(sMutex);
StaticMonitorAutoLock lock(sMonitor);
if (!sInstance) {
return;
}
@ -283,7 +295,7 @@ void SharedSurfacesParent::RemoveTracking(
/* static */
bool SharedSurfacesParent::AgeOneGenerationLocked(
nsTArray<RefPtr<SourceSurfaceSharedDataWrapper>>& aExpired,
const StaticMutexAutoLock& aAutoLock) {
const StaticMonitorAutoLock& aAutoLock) {
if (sInstance->mTracker.IsEmptyLocked(aAutoLock)) {
return false;
}
@ -296,7 +308,7 @@ bool SharedSurfacesParent::AgeOneGenerationLocked(
/* static */
bool SharedSurfacesParent::AgeOneGeneration(
nsTArray<RefPtr<SourceSurfaceSharedDataWrapper>>& aExpired) {
StaticMutexAutoLock lock(sMutex);
StaticMonitorAutoLock lock(sMonitor);
if (!sInstance) {
return false;
}
@ -323,7 +335,7 @@ void SharedSurfacesParent::ExpireMap(
/* static */
void SharedSurfacesParent::AccumulateMemoryReport(
base::ProcessId aPid, SharedSurfacesMemoryReport& aReport) {
StaticMutexAutoLock lock(sMutex);
StaticMonitorAutoLock lock(sMonitor);
if (!sInstance) {
return;
}
@ -352,7 +364,7 @@ bool SharedSurfacesParent::AccumulateMemoryReport(
return false;
}
StaticMutexAutoLock lock(sMutex);
StaticMonitorAutoLock lock(sMonitor);
if (!sInstance) {
return true;
}

View File

@ -9,7 +9,7 @@
#include <stdint.h> // for uint32_t
#include "mozilla/Attributes.h" // for override
#include "mozilla/StaticMutex.h" // for StaticMutex
#include "mozilla/StaticMonitor.h" // for StaticMutex
#include "mozilla/StaticPtr.h" // for StaticAutoPtr
#include "mozilla/RefPtr.h" // for already_AddRefed
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
@ -78,20 +78,20 @@ class SharedSurfacesParent final {
gfx::SourceSurfaceSharedData* aSurface);
static void AddTrackingLocked(gfx::SourceSurfaceSharedDataWrapper* aSurface,
const StaticMutexAutoLock& aAutoLock);
const StaticMonitorAutoLock& aAutoLock);
static void RemoveTrackingLocked(
gfx::SourceSurfaceSharedDataWrapper* aSurface,
const StaticMutexAutoLock& aAutoLock);
const StaticMonitorAutoLock& aAutoLock);
static bool AgeOneGenerationLocked(
nsTArray<RefPtr<gfx::SourceSurfaceSharedDataWrapper>>& aExpired,
const StaticMutexAutoLock& aAutoLock);
const StaticMonitorAutoLock& aAutoLock);
static void ExpireMap(
nsTArray<RefPtr<gfx::SourceSurfaceSharedDataWrapper>>& aExpired);
static StaticMutex sMutex;
static StaticMonitor sMonitor;
static StaticAutoPtr<SharedSurfacesParent> sInstance;
@ -100,28 +100,28 @@ class SharedSurfacesParent final {
class MappingTracker final
: public ExpirationTrackerImpl<gfx::SourceSurfaceSharedDataWrapper, 4,
StaticMutex, StaticMutexAutoLock> {
StaticMonitor, StaticMonitorAutoLock> {
public:
explicit MappingTracker(uint32_t aExpirationTimeoutMS,
nsIEventTarget* aEventTarget)
: ExpirationTrackerImpl<gfx::SourceSurfaceSharedDataWrapper, 4,
StaticMutex, StaticMutexAutoLock>(
StaticMonitor, StaticMonitorAutoLock>(
aExpirationTimeoutMS, "SharedMappingTracker", aEventTarget) {}
void TakeExpired(
nsTArray<RefPtr<gfx::SourceSurfaceSharedDataWrapper>>& aExpired,
const StaticMutexAutoLock& aAutoLock);
const StaticMonitorAutoLock& aAutoLock);
protected:
void NotifyExpiredLocked(gfx::SourceSurfaceSharedDataWrapper* aSurface,
const StaticMutexAutoLock& aAutoLock) override;
const StaticMonitorAutoLock& aAutoLock) override;
void NotifyHandlerEndLocked(const StaticMutexAutoLock& aAutoLock) override {
}
void NotifyHandlerEndLocked(
const StaticMonitorAutoLock& aAutoLock) override {}
void NotifyHandlerEnd() override;
StaticMutex& GetMutex() override { return sMutex; }
StaticMonitor& GetMutex() override { return sMonitor; }
nsTArray<RefPtr<gfx::SourceSurfaceSharedDataWrapper>> mExpired;
};