Bug 1829026 - Update CanvasTranslator to work with DrawTargetWebgl. r=aosmond

This adds the necessary infrastructure for CanvasTranslator to allocate DrawTargetWebgl
instead of just allocating TextureData, and to use RemoteTextureMap to handle sending
the DrawTargetWebgl frames to the compositor.

This optimizes snapshot transport to use fewer copies to and from shmems when we know
the snapshot contents can be sourced from a shmem.

This adds a blocking mechanism separate from deactivation so that existing DrawTargetWebgls
can continue processing events while denying further ones from being created in the event
that allocating further DrawTargetWebgls might cause problems, but so that we don't disrupt
canvases that are already in flight.

PersistentBufferProviderAccelerated still remains the buffer provider for the new setup,
but just allocates a single RecordedTextureData internally. Since DrawTargetWebgl already
does its own swap chain management internally, we do not want to use the multiple texture
client strategy that PersistentBufferProviderShared does.

This adds a fallback mechanism such that if DrawTargetWebgl allocation fails, a TextureData
is allocated instead that still sends results to RemoteTextureMap. This has the advantage
that we don't need to synchronously block in the content process to verify if acceleration
succeeded, as the costs of such blocking are rather extreme and we must still produce the
rendered frame to ensure the user sees the correct result if the speculative acceleration
failed. It then notifies the content process asynchronously via the refresh mechanism to
try to recreate a non-accelerated buffer provider when it is ready.

There is one additional hitch in RemoteTextureMap that we need to add a mechanism to deal
with the setup of the RemoteTextureOwner. When display list building initially needs to get
the remote texture, the RemoteTextureOwner might not exist yet. In this case, we need to add
a block to ensure we wait for that to occur so that we do not render an erroneous result.
Previously, this block was handled in ClientWebGLContext. Since that is no longer used,
the block must be reinstated somewhere else until a non-blocking mechanism for display list
building to proceed with a stub texture host wrapper can be implemented.

Currently this leaves the gfx.canvas.remote and gfx.canvas.accelerated prefs as separate
toggles rather than trying to lump everything into one mechanism. While this may be desirable
in the future, currently Direct2D remote canvas is a separate acceleration mechanism that
needs to co-exist with the WebGL acceleration, and so being able to toggle both on or off
for testing is desirable.

Differential Revision: https://phabricator.services.mozilla.com/D194352
This commit is contained in:
Lee Salzman 2023-12-18 18:10:46 +00:00
Родитель 46b4579090
Коммит 5b34ab7937
30 изменённых файлов: 1001 добавлений и 265 удалений

Просмотреть файл

@ -64,7 +64,6 @@
#include "nsIMemoryReporter.h"
#include "nsStyleUtil.h"
#include "CanvasImageCache.h"
#include "DrawTargetWebgl.h"
#include <algorithm>
@ -1357,6 +1356,7 @@ bool CanvasRenderingContext2D::CopyBufferProvider(
}
aTarget.CopySurface(snapshot, aCopyRect, IntPoint());
aOld.ReturnSnapshot(snapshot.forget());
return true;
}
@ -1651,13 +1651,22 @@ bool CanvasRenderingContext2D::TryAcceleratedTarget(
if (!mAllowAcceleration || GetEffectiveWillReadFrequently()) {
return false;
}
aOutDT = DrawTargetWebgl::Create(GetSize(), GetSurfaceFormat());
if (!aOutDT) {
if (!mCanvasElement) {
return false;
}
aOutProvider = new PersistentBufferProviderAccelerated(aOutDT);
return true;
WindowRenderer* renderer = WindowRendererFromCanvasElement(mCanvasElement);
if (!renderer) {
return false;
}
aOutProvider = PersistentBufferProviderAccelerated::Create(
GetSize(), GetSurfaceFormat(), renderer->AsKnowsCompositor());
if (!aOutProvider) {
return false;
}
aOutDT = aOutProvider->BorrowDrawTarget(IntRect());
MOZ_ASSERT(aOutDT);
return !!aOutDT;
}
bool CanvasRenderingContext2D::TrySharedTarget(

Просмотреть файл

@ -239,12 +239,9 @@ void DrawTargetWebgl::ClearSnapshot(bool aCopyOnWrite, bool aNeedHandle) {
DrawTargetWebgl::~DrawTargetWebgl() {
ClearSnapshot(false);
if (mSharedContext) {
if (mShmem.IsWritable()) {
// Force any Skia snapshots to copy the shmem before it deallocs.
// Force any Skia snapshots to copy the shmem before it deallocs.
if (mSkia) {
mSkia->DetachAllSnapshots();
if (mShmemAllocator && mShmemAllocator->CanSend()) {
mShmemAllocator->DeallocShmem(mShmem);
}
}
mSharedContext->ClearLastTexture(true);
mClipMask = nullptr;
@ -373,7 +370,6 @@ void SharedContextWebgl::ClearCachesIfNecessary() {
// Try to initialize a new WebGL context. Verifies that the requested size does
// not exceed the available texture limits and that shader creation succeeded.
bool DrawTargetWebgl::Init(const IntSize& size, const SurfaceFormat format,
ipc::IProtocol* aShmemAllocator,
const RefPtr<SharedContextWebgl>& aSharedContext) {
MOZ_ASSERT(format == SurfaceFormat::B8G8R8A8 ||
format == SurfaceFormat::B8G8R8X8);
@ -398,24 +394,32 @@ bool DrawTargetWebgl::Init(const IntSize& size, const SurfaceFormat format,
return false;
}
mShmemAllocator = aShmemAllocator;
if (mShmemAllocator && mShmemAllocator->CanSend()) {
size_t byteSize = layers::ImageDataSerializer::ComputeRGBBufferSize(
mSize, SurfaceFormat::B8G8R8A8);
if (byteSize) {
(void)mShmemAllocator->AllocUnsafeShmem(byteSize, &mShmem);
}
size_t byteSize = layers::ImageDataSerializer::ComputeRGBBufferSize(
mSize, SurfaceFormat::B8G8R8A8);
if (byteSize == 0) {
return false;
}
size_t shmemSize = mozilla::ipc::SharedMemory::PageAlignedSize(byteSize);
if (NS_WARN_IF(shmemSize > UINT32_MAX)) {
MOZ_ASSERT_UNREACHABLE("Buffer too big?");
return false;
}
auto shmem = MakeRefPtr<mozilla::ipc::SharedMemoryBasic>();
if (NS_WARN_IF(!shmem->Create(shmemSize)) ||
NS_WARN_IF(!shmem->Map(shmemSize))) {
return false;
}
mShmem = std::move(shmem);
mShmemSize = shmemSize;
mSkia = new DrawTargetSkia;
if (mShmem.IsWritable()) {
auto stride = layers::ImageDataSerializer::ComputeRGBStride(
SurfaceFormat::B8G8R8A8, size.width);
if (!mSkia->Init(mShmem.get<uint8_t>(), size, stride,
SurfaceFormat::B8G8R8A8, true)) {
return false;
}
} else if (!mSkia->Init(size, SurfaceFormat::B8G8R8A8)) {
auto stride = layers::ImageDataSerializer::ComputeRGBStride(
SurfaceFormat::B8G8R8A8, size.width);
if (!mSkia->Init(reinterpret_cast<uint8_t*>(mShmem->memory()), size, stride,
SurfaceFormat::B8G8R8A8, true)) {
return false;
}
@ -858,7 +862,6 @@ bool DrawTargetWebgl::CanCreate(const IntSize& aSize, SurfaceFormat aFormat) {
already_AddRefed<DrawTargetWebgl> DrawTargetWebgl::Create(
const IntSize& aSize, SurfaceFormat aFormat,
ipc::IProtocol* aShmemAllocator,
const RefPtr<SharedContextWebgl>& aSharedContext) {
// Validate the size and format.
if (!CanCreate(aSize, aFormat)) {
@ -866,8 +869,7 @@ already_AddRefed<DrawTargetWebgl> DrawTargetWebgl::Create(
}
RefPtr<DrawTargetWebgl> dt = new DrawTargetWebgl;
if (!dt->Init(aSize, aFormat, aShmemAllocator, aSharedContext) ||
!dt->IsValid()) {
if (!dt->Init(aSize, aFormat, aSharedContext) || !dt->IsValid()) {
return nullptr;
}

Просмотреть файл

@ -14,7 +14,7 @@
#include "mozilla/LinkedList.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/ThreadLocal.h"
#include "mozilla/ipc/Shmem.h"
#include "mozilla/ipc/SharedMemoryBasic.h"
#include "mozilla/layers/LayersTypes.h"
#include <vector>
@ -352,10 +352,11 @@ class DrawTargetWebgl : public DrawTarget, public SupportsWeakPtr {
// Skia DT pointing to the same pixel data, but without any applied clips.
RefPtr<DrawTargetSkia> mSkiaNoClip;
// The Shmem backing the Skia DT, if applicable.
mozilla::ipc::Shmem mShmem;
mozilla::ipc::IProtocol* mShmemAllocator = nullptr;
RefPtr<mozilla::ipc::SharedMemoryBasic> mShmem;
// The currently cached snapshot of the WebGL context
RefPtr<DataSourceSurface> mSnapshot;
// The mappable size of mShmem.
uint32_t mShmemSize = 0;
// Whether the framebuffer is still in the initially clear state.
bool mIsClear = true;
// Whether or not the Skia target has valid contents and is being drawn to
@ -431,11 +432,9 @@ class DrawTargetWebgl : public DrawTarget, public SupportsWeakPtr {
static bool CanCreate(const IntSize& aSize, SurfaceFormat aFormat);
static already_AddRefed<DrawTargetWebgl> Create(
const IntSize& aSize, SurfaceFormat aFormat,
ipc::IProtocol* aShmemAllocator,
const RefPtr<SharedContextWebgl>& aSharedContext);
bool Init(const IntSize& aSize, SurfaceFormat aFormat,
ipc::IProtocol* aShmemAllocator,
const RefPtr<SharedContextWebgl>& aSharedContext);
bool IsValid() const override;
@ -565,10 +564,13 @@ class DrawTargetWebgl : public DrawTarget, public SupportsWeakPtr {
return stream.str();
}
Maybe<mozilla::ipc::Shmem> GetShmem() const {
return mShmem.IsWritable() ? Some(mShmem) : Nothing();
mozilla::ipc::SharedMemoryBasic::Handle TakeShmemHandle() const {
return mShmem ? mShmem->TakeHandle()
: mozilla::ipc::SharedMemoryBasic::NULLHandle();
}
uint32_t GetShmemSize() const { return mShmemSize; }
private:
bool SupportsPattern(const Pattern& aPattern) {
return mSharedContext->SupportsPattern(aPattern);

Просмотреть файл

@ -238,7 +238,7 @@ fuzzy(0-1,0-2) skip-if(cocoaWidget||winWidget||gtkWidget) needs-focus == drawFoc
# Check that captureStream() displays in a local video element
== capturestream.html wrapper.html?green.png
fuzzy-if(azureSkia,0-16,0-20) fuzzy-if(Android,0-3,0-40) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-1) == 1177726-text-stroke-bounds.html 1177726-text-stroke-bounds-ref.html
fuzzy(0-235,0-3104) == 1177726-text-stroke-bounds.html 1177726-text-stroke-bounds-ref.html
# Bug 1366027
== clipped-dash-stroke-rect.html clipped-dash-stroke-rect-ref.html

Просмотреть файл

@ -165,7 +165,13 @@ void CanvasManagerChild::DeactivateCanvas() {
}
}
void CanvasManagerChild::BlockCanvas() { mBlocked = true; }
RefPtr<layers::CanvasChild> CanvasManagerChild::GetCanvasChild() {
if (mBlocked) {
return nullptr;
}
if (!mActive) {
MOZ_ASSERT(!mCanvasChild);
return nullptr;

Просмотреть файл

@ -49,6 +49,7 @@ class CanvasManagerChild final : public PCanvasManagerChild {
void EndCanvasTransaction();
void ClearCachedResources();
void DeactivateCanvas();
void BlockCanvas();
RefPtr<layers::CanvasChild> GetCanvasChild();
@ -63,6 +64,7 @@ class CanvasManagerChild final : public PCanvasManagerChild {
RefPtr<webgpu::WebGPUChild> mWebGPUChild;
const uint32_t mId;
bool mActive = true;
bool mBlocked = false;
static MOZ_THREAD_LOCAL(CanvasManagerChild*) sLocalManager;
static Atomic<uint32_t> sNextId;

Просмотреть файл

@ -360,14 +360,15 @@ mozilla::ipc::IPCResult GPUParent::RecvInit(
// here that would normally be initialized there.
SkGraphics::Init();
if (gfxVars::RemoteCanvasEnabled()) {
bool useRemoteCanvas =
gfxVars::RemoteCanvasEnabled() || gfxVars::UseAcceleratedCanvas2D();
if (useRemoteCanvas) {
gfxGradientCache::Init();
}
#if defined(XP_WIN)
if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
if (DeviceManagerDx::Get()->CreateCompositorDevices() &&
gfxVars::RemoteCanvasEnabled()) {
if (DeviceManagerDx::Get()->CreateCompositorDevices() && useRemoteCanvas) {
if (DeviceManagerDx::Get()->CreateCanvasDevice()) {
gfxDWriteFont::InitDWriteSupport();
} else {

Просмотреть файл

@ -43,6 +43,7 @@ CanvasDrawEventRecorder::CanvasDrawEventRecorder() {
}
bool CanvasDrawEventRecorder::Init(TextureType aTextureType,
gfx::BackendType aBackendType,
UniquePtr<Helpers> aHelpers) {
mHelpers = std::move(aHelpers);
@ -91,7 +92,8 @@ bool CanvasDrawEventRecorder::Init(TextureType aTextureType,
return false;
}
if (!mHelpers->InitTranslator(aTextureType, std::move(header->handle),
if (!mHelpers->InitTranslator(aTextureType, aBackendType,
std::move(header->handle),
std::move(bufferHandles), mDefaultBufferSize,
std::move(readerSem), std::move(writerSem),
/* aUseIPDLThread */ false)) {

Просмотреть файл

@ -67,16 +67,13 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate,
public:
virtual ~Helpers() = default;
virtual bool InitTranslator(const TextureType& aTextureType,
Handle&& aReadHandle,
nsTArray<Handle>&& aBufferHandles,
const uint64_t& aBufferSize,
CrossProcessSemaphoreHandle&& aReaderSem,
CrossProcessSemaphoreHandle&& aWriterSem,
const bool& aUseIPDLThread) = 0;
virtual bool InitTranslator(
TextureType aTextureType, gfx::BackendType aBackendType,
Handle&& aReadHandle, nsTArray<Handle>&& aBufferHandles,
uint64_t aBufferSize, CrossProcessSemaphoreHandle&& aReaderSem,
CrossProcessSemaphoreHandle&& aWriterSem, bool aUseIPDLThread) = 0;
virtual bool AddBuffer(Handle&& aBufferHandle,
const uint64_t& aBufferSize) = 0;
virtual bool AddBuffer(Handle&& aBufferHandle, uint64_t aBufferSize) = 0;
/**
* @returns true if the reader of the CanvasEventRingBuffer has permanently
@ -90,7 +87,8 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate,
virtual bool RestartReader() = 0;
};
bool Init(TextureType aTextureType, UniquePtr<Helpers> aHelpers);
bool Init(TextureType aTextureType, gfx::BackendType aBackendType,
UniquePtr<Helpers> aHelpers);
/**
* Record an event for processing by the CanvasParent's CanvasTranslator.

Просмотреть файл

@ -6,6 +6,7 @@
#include "PersistentBufferProvider.h"
#include "mozilla/layers/RemoteTextureMap.h"
#include "mozilla/layers/TextureClient.h"
#include "mozilla/layers/TextureForwarder.h"
#include "mozilla/gfx/gfxVars.h"
@ -96,65 +97,149 @@ PersistentBufferProviderBasic::Create(gfx::IntSize aSize,
return provider.forget();
}
static already_AddRefed<TextureClient> CreateTexture(
KnowsCompositor* aKnowsCompositor, gfx::SurfaceFormat aFormat,
gfx::IntSize aSize, bool aWillReadFrequently = false,
Maybe<RemoteTextureOwnerId> aRemoteTextureOwnerId = {}) {
TextureAllocationFlags flags = ALLOC_DEFAULT;
if (aWillReadFrequently) {
flags = TextureAllocationFlags(flags | ALLOC_DO_NOT_ACCELERATE);
}
if (aRemoteTextureOwnerId) {
flags = TextureAllocationFlags(flags | ALLOC_FORCE_REMOTE);
}
RefPtr<TextureClient> tc = TextureClient::CreateForDrawing(
aKnowsCompositor, aFormat, aSize, BackendSelector::Canvas,
TextureFlags::DEFAULT | TextureFlags::NON_BLOCKING_READ_LOCK, flags);
if (tc && aRemoteTextureOwnerId) {
if (TextureData* td = tc->GetInternalData()) {
td->SetRemoteTextureOwnerId(*aRemoteTextureOwnerId);
}
}
return tc.forget();
}
// static
already_AddRefed<PersistentBufferProviderAccelerated>
PersistentBufferProviderAccelerated::Create(gfx::IntSize aSize,
gfx::SurfaceFormat aFormat,
KnowsCompositor* aKnowsCompositor) {
if (!DrawTargetWebgl::CanCreate(aSize, aFormat)) {
return nullptr;
}
if (!aKnowsCompositor || !aKnowsCompositor->GetTextureForwarder() ||
!aKnowsCompositor->GetTextureForwarder()->IPCOpen()) {
return nullptr;
}
auto remoteTextureOwnerId = RemoteTextureOwnerId::GetNext();
RefPtr<TextureClient> texture = CreateTexture(
aKnowsCompositor, aFormat, aSize, false, Some(remoteTextureOwnerId));
if (!texture) {
return nullptr;
}
RefPtr<PersistentBufferProviderAccelerated> provider =
new PersistentBufferProviderAccelerated(texture);
return provider.forget();
}
PersistentBufferProviderAccelerated::PersistentBufferProviderAccelerated(
DrawTarget* aDt)
: PersistentBufferProviderBasic(aDt) {
const RefPtr<TextureClient>& aTexture)
: mTexture(aTexture) {
MOZ_COUNT_CTOR(PersistentBufferProviderAccelerated);
MOZ_ASSERT(aDt->GetBackendType() == BackendType::WEBGL);
}
PersistentBufferProviderAccelerated::~PersistentBufferProviderAccelerated() {
MOZ_COUNT_DTOR(PersistentBufferProviderAccelerated);
Destroy();
}
inline gfx::DrawTargetWebgl*
PersistentBufferProviderAccelerated::GetDrawTargetWebgl() const {
return static_cast<gfx::DrawTargetWebgl*>(mDrawTarget.get());
}
void PersistentBufferProviderAccelerated::Destroy() {
mSnapshot = nullptr;
mDrawTarget = nullptr;
Maybe<layers::SurfaceDescriptor>
PersistentBufferProviderAccelerated::GetFrontBuffer() {
return GetDrawTargetWebgl()->GetFrontBuffer();
if (mTexture) {
if (mTexture->IsLocked()) {
MOZ_ASSERT(false);
mTexture->Unlock();
}
mTexture = nullptr;
}
}
already_AddRefed<gfx::DrawTarget>
PersistentBufferProviderAccelerated::BorrowDrawTarget(
const gfx::IntRect& aPersistedRect) {
GetDrawTargetWebgl()->BeginFrame(aPersistedRect);
return PersistentBufferProviderBasic::BorrowDrawTarget(aPersistedRect);
if (!mDrawTarget) {
if (!mTexture->Lock(OpenMode::OPEN_READ_WRITE)) {
return nullptr;
}
mDrawTarget = mTexture->BorrowDrawTarget();
if (mDrawTarget) {
mDrawTarget->ClearRect(Rect(0, 0, 0, 0));
if (!mDrawTarget->IsValid()) {
mDrawTarget = nullptr;
}
}
}
return do_AddRef(mDrawTarget);
}
bool PersistentBufferProviderAccelerated::ReturnDrawTarget(
already_AddRefed<gfx::DrawTarget> aDT) {
bool result = PersistentBufferProviderBasic::ReturnDrawTarget(std::move(aDT));
GetDrawTargetWebgl()->EndFrame();
return result;
{
RefPtr<gfx::DrawTarget> dt(aDT);
MOZ_ASSERT(mDrawTarget == dt);
if (!mDrawTarget) {
return false;
}
mDrawTarget = nullptr;
}
mTexture->Unlock();
return true;
}
already_AddRefed<gfx::SourceSurface>
PersistentBufferProviderAccelerated::BorrowSnapshot(gfx::DrawTarget* aTarget) {
mSnapshot = GetDrawTargetWebgl()->GetOptimizedSnapshot(aTarget);
if (mDrawTarget) {
MOZ_ASSERT(mTexture->IsLocked());
} else {
if (mTexture->IsLocked()) {
MOZ_ASSERT(false);
return nullptr;
}
if (!mTexture->Lock(OpenMode::OPEN_READ)) {
return nullptr;
}
}
mSnapshot = mTexture->BorrowSnapshot();
return do_AddRef(mSnapshot);
}
bool PersistentBufferProviderAccelerated::RequiresRefresh() const {
return GetDrawTargetWebgl()->RequiresRefresh();
}
void PersistentBufferProviderAccelerated::OnMemoryPressure() {
GetDrawTargetWebgl()->OnMemoryPressure();
}
static already_AddRefed<TextureClient> CreateTexture(
KnowsCompositor* aKnowsCompositor, gfx::SurfaceFormat aFormat,
gfx::IntSize aSize, bool aWillReadFrequently) {
TextureAllocationFlags flags = ALLOC_DEFAULT;
if (aWillReadFrequently) {
flags = TextureAllocationFlags(flags | ALLOC_DO_NOT_ACCELERATE);
void PersistentBufferProviderAccelerated::ReturnSnapshot(
already_AddRefed<gfx::SourceSurface> aSnapshot) {
RefPtr<SourceSurface> snapshot = aSnapshot;
MOZ_ASSERT(!snapshot || snapshot == mSnapshot);
snapshot = nullptr;
mTexture->ReturnSnapshot(mSnapshot.forget());
if (!mDrawTarget) {
mTexture->Unlock();
}
return TextureClient::CreateForDrawing(
aKnowsCompositor, aFormat, aSize, BackendSelector::Canvas,
TextureFlags::DEFAULT | TextureFlags::NON_BLOCKING_READ_LOCK, flags);
}
Maybe<SurfaceDescriptor> PersistentBufferProviderAccelerated::GetFrontBuffer() {
SurfaceDescriptor desc;
if (mTexture->GetInternalData()->Serialize(desc)) {
return Some(desc);
}
return Nothing();
}
bool PersistentBufferProviderAccelerated::RequiresRefresh() const {
return mTexture->GetInternalData()->RequiresRefresh();
}
// static
@ -198,7 +283,6 @@ PersistentBufferProviderShared::PersistentBufferProviderShared(
gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
KnowsCompositor* aKnowsCompositor, RefPtr<TextureClient>& aTexture,
bool aWillReadFrequently)
: mSize(aSize),
mFormat(aFormat),
mKnowsCompositor(aKnowsCompositor),

Просмотреть файл

@ -24,11 +24,11 @@ class ClientWebGLContext;
namespace gfx {
class SourceSurface;
class DrawTarget;
class DrawTargetWebgl;
} // namespace gfx
namespace layers {
struct RemoteTextureOwnerId;
class TextureClient;
/**
@ -104,12 +104,7 @@ class PersistentBufferProvider : public RefCounted<PersistentBufferProvider>,
*/
virtual bool RequiresRefresh() const { return false; }
/**
* Provide a WebGL front buffer for compositing, if available.
*/
virtual Maybe<layers::SurfaceDescriptor> GetFrontBuffer() {
return Nothing();
}
virtual Maybe<SurfaceDescriptor> GetFrontBuffer() { return Nothing(); }
};
class PersistentBufferProviderBasic : public PersistentBufferProvider {
@ -146,18 +141,17 @@ class PersistentBufferProviderBasic : public PersistentBufferProvider {
RefPtr<gfx::SourceSurface> mSnapshot;
};
class PersistentBufferProviderAccelerated
: public PersistentBufferProviderBasic {
class PersistentBufferProviderAccelerated : public PersistentBufferProvider {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PersistentBufferProviderAccelerated,
override)
explicit PersistentBufferProviderAccelerated(gfx::DrawTarget* aTarget);
static already_AddRefed<PersistentBufferProviderAccelerated> Create(
gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
KnowsCompositor* aKnowsCompositor);
bool IsAccelerated() const override { return true; }
Maybe<layers::SurfaceDescriptor> GetFrontBuffer() override;
already_AddRefed<gfx::DrawTarget> BorrowDrawTarget(
const gfx::IntRect& aPersistedRect) override;
@ -166,14 +160,27 @@ class PersistentBufferProviderAccelerated
already_AddRefed<gfx::SourceSurface> BorrowSnapshot(
gfx::DrawTarget* aTarget) override;
void ReturnSnapshot(already_AddRefed<gfx::SourceSurface> aSnapshot) override;
bool PreservesDrawingState() const override { return true; }
void OnShutdown() override { Destroy(); }
Maybe<SurfaceDescriptor> GetFrontBuffer() override;
bool RequiresRefresh() const override;
void OnMemoryPressure() override;
protected:
explicit PersistentBufferProviderAccelerated(
const RefPtr<TextureClient>& aTexture);
~PersistentBufferProviderAccelerated() override;
gfx::DrawTargetWebgl* GetDrawTargetWebgl() const;
void Destroy();
RefPtr<TextureClient> mTexture;
RefPtr<gfx::DrawTarget> mDrawTarget;
RefPtr<gfx::SourceSurface> mSnapshot;
};
/**

Просмотреть файл

@ -44,7 +44,8 @@ const EventType CHECKPOINT = EventType(EventType::LAST + 13);
const EventType PAUSE_TRANSLATION = EventType(EventType::LAST + 14);
const EventType RECYCLE_BUFFER = EventType(EventType::LAST + 15);
const EventType DROP_BUFFER = EventType(EventType::LAST + 16);
const EventType LAST_CANVAS_EVENT_TYPE = DROP_BUFFER;
const EventType PREPARE_SHMEM = EventType(EventType::LAST + 17);
const EventType LAST_CANVAS_EVENT_TYPE = PREPARE_SHMEM;
class RecordedCanvasBeginTransaction final
: public RecordedEventDerived<RecordedCanvasBeginTransaction> {
@ -138,10 +139,12 @@ RecordedCanvasFlush::RecordedCanvasFlush(S& aStream)
class RecordedTextureLock final
: public RecordedEventDerived<RecordedTextureLock> {
public:
RecordedTextureLock(int64_t aTextureId, const OpenMode aMode)
RecordedTextureLock(int64_t aTextureId, const OpenMode aMode,
RemoteTextureId aId)
: RecordedEventDerived(TEXTURE_LOCK),
mTextureId(aTextureId),
mMode(aMode) {}
mMode(aMode),
mLastRemoteTextureId(aId) {}
template <class S>
MOZ_IMPLICIT RecordedTextureLock(S& aStream);
@ -156,16 +159,14 @@ class RecordedTextureLock final
private:
int64_t mTextureId;
OpenMode mMode;
RemoteTextureId mLastRemoteTextureId;
};
inline bool RecordedTextureLock::PlayCanvasEvent(
CanvasTranslator* aTranslator) const {
TextureData* textureData = aTranslator->LookupTextureData(mTextureId);
if (!textureData) {
if (!aTranslator->LockTexture(mTextureId, mMode, mLastRemoteTextureId)) {
return false;
}
textureData->Lock(mMode);
return true;
}
@ -173,6 +174,7 @@ template <class S>
void RecordedTextureLock::Record(S& aStream) const {
WriteElement(aStream, mTextureId);
WriteElement(aStream, mMode);
WriteElement(aStream, mLastRemoteTextureId.mId);
}
template <class S>
@ -181,13 +183,16 @@ RecordedTextureLock::RecordedTextureLock(S& aStream)
ReadElement(aStream, mTextureId);
ReadElementConstrained(aStream, mMode, OpenMode::OPEN_NONE,
OpenMode::OPEN_READ_WRITE_ASYNC);
ReadElement(aStream, mLastRemoteTextureId.mId);
}
class RecordedTextureUnlock final
: public RecordedEventDerived<RecordedTextureUnlock> {
public:
explicit RecordedTextureUnlock(int64_t aTextureId)
: RecordedEventDerived(TEXTURE_UNLOCK), mTextureId(aTextureId) {}
explicit RecordedTextureUnlock(int64_t aTextureId, RemoteTextureId aId)
: RecordedEventDerived(TEXTURE_UNLOCK),
mTextureId(aTextureId),
mLastRemoteTextureId(aId) {}
template <class S>
MOZ_IMPLICIT RecordedTextureUnlock(S& aStream);
@ -201,28 +206,28 @@ class RecordedTextureUnlock final
private:
int64_t mTextureId;
RemoteTextureId mLastRemoteTextureId;
};
inline bool RecordedTextureUnlock::PlayCanvasEvent(
CanvasTranslator* aTranslator) const {
TextureData* textureData = aTranslator->LookupTextureData(mTextureId);
if (!textureData) {
if (!aTranslator->UnlockTexture(mTextureId, mLastRemoteTextureId)) {
return false;
}
textureData->Unlock();
return true;
}
template <class S>
void RecordedTextureUnlock::Record(S& aStream) const {
WriteElement(aStream, mTextureId);
WriteElement(aStream, mLastRemoteTextureId.mId);
}
template <class S>
RecordedTextureUnlock::RecordedTextureUnlock(S& aStream)
: RecordedEventDerived(TEXTURE_UNLOCK) {
ReadElement(aStream, mTextureId);
ReadElement(aStream, mLastRemoteTextureId.mId);
}
class RecordedCacheDataSurface final
@ -486,8 +491,11 @@ RecordedDeviceChangeAcknowledged::RecordedDeviceChangeAcknowledged(S& aStream)
class RecordedNextTextureId final
: public RecordedEventDerived<RecordedNextTextureId> {
public:
explicit RecordedNextTextureId(int64_t aNextTextureId)
: RecordedEventDerived(NEXT_TEXTURE_ID), mNextTextureId(aNextTextureId) {}
RecordedNextTextureId(int64_t aNextTextureId,
RemoteTextureOwnerId aRemoteTextureOwnerId)
: RecordedEventDerived(NEXT_TEXTURE_ID),
mNextTextureId(aNextTextureId),
mRemoteTextureOwnerId(aRemoteTextureOwnerId) {}
template <class S>
MOZ_IMPLICIT RecordedNextTextureId(S& aStream);
@ -500,24 +508,28 @@ class RecordedNextTextureId final
std::string GetName() const final { return "RecordedNextTextureId"; }
private:
int64_t mNextTextureId;
int64_t mNextTextureId = 0;
RemoteTextureOwnerId mRemoteTextureOwnerId;
RemoteTextureId mRemoteTextureId;
};
inline bool RecordedNextTextureId::PlayCanvasEvent(
CanvasTranslator* aTranslator) const {
aTranslator->SetNextTextureId(mNextTextureId);
aTranslator->SetNextTextureId(mNextTextureId, mRemoteTextureOwnerId);
return true;
}
template <class S>
void RecordedNextTextureId::Record(S& aStream) const {
WriteElement(aStream, mNextTextureId);
WriteElement(aStream, mRemoteTextureOwnerId.mId);
}
template <class S>
RecordedNextTextureId::RecordedNextTextureId(S& aStream)
: RecordedEventDerived(NEXT_TEXTURE_ID) {
ReadElement(aStream, mNextTextureId);
ReadElement(aStream, mRemoteTextureOwnerId.mId);
}
class RecordedTextureDestruction final
@ -537,7 +549,7 @@ class RecordedTextureDestruction final
std::string GetName() const final { return "RecordedTextureDestruction"; }
private:
int64_t mTextureId;
int64_t mTextureId = 0;
};
inline bool RecordedTextureDestruction::PlayCanvasEvent(
@ -638,6 +650,43 @@ class RecordedDropBuffer final
std::string GetName() const final { return "RecordedDropAndMoveNextBuffer"; }
};
class RecordedPrepareShmem final
: public RecordedEventDerived<RecordedPrepareShmem> {
public:
explicit RecordedPrepareShmem(int64_t aTextureId)
: RecordedEventDerived(PREPARE_SHMEM), mTextureId(aTextureId) {}
template <class S>
MOZ_IMPLICIT RecordedPrepareShmem(S& aStream);
bool PlayCanvasEvent(CanvasTranslator* aTranslator) const;
template <class S>
void Record(S& aStream) const;
std::string GetName() const final { return "RecordedPrepareShmem"; }
private:
int64_t mTextureId = 0;
};
inline bool RecordedPrepareShmem::PlayCanvasEvent(
CanvasTranslator* aTranslator) const {
aTranslator->PrepareShmem(mTextureId);
return true;
}
template <class S>
void RecordedPrepareShmem::Record(S& aStream) const {
WriteElement(aStream, mTextureId);
}
template <class S>
RecordedPrepareShmem::RecordedPrepareShmem(S& aStream)
: RecordedEventDerived(PREPARE_SHMEM) {
ReadElement(aStream, mTextureId);
}
#define FOR_EACH_CANVAS_EVENT(f) \
f(CANVAS_BEGIN_TRANSACTION, RecordedCanvasBeginTransaction); \
f(CANVAS_END_TRANSACTION, RecordedCanvasEndTransaction); \
@ -655,7 +704,8 @@ class RecordedDropBuffer final
f(CHECKPOINT, RecordedCheckpoint); \
f(PAUSE_TRANSLATION, RecordedPauseTranslation); \
f(RECYCLE_BUFFER, RecordedRecycleBuffer); \
f(DROP_BUFFER, RecordedDropBuffer);
f(DROP_BUFFER, RecordedDropBuffer); \
f(PREPARE_SHMEM, RecordedPrepareShmem);
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -217,7 +217,7 @@ void RemoteTextureMap::Shutdown() {
}
}
RemoteTextureMap::RemoteTextureMap() : mMonitor("D3D11TextureMap::mMonitor") {}
RemoteTextureMap::RemoteTextureMap() : mMonitor("RemoteTextureMap::mMonitor") {}
RemoteTextureMap::~RemoteTextureMap() = default;
@ -314,17 +314,7 @@ void RemoteTextureMap::PushTexture(
// used by WebRender anymore.
if (front->mTextureHost &&
front->mTextureHost->NumCompositableRefs() == 0) {
// Recycle SharedTexture
if (front->mResourceWrapper) {
owner->mRecycledSharedTextures.push(
std::move(front->mResourceWrapper));
}
// Recycle BufferTextureData
if (!(front->mTextureHost->GetFlags() & TextureFlags::DUMMY_TEXTURE) &&
(front->mTextureData &&
front->mTextureData->AsBufferTextureData())) {
owner->mRecycledTextures.push(std::move(front->mTextureData));
}
owner->mReleasingTextureDataHolders.push_back(std::move(front));
owner->mUsingTextureDataHolders.pop_front();
} else if (front->mTextureHost &&
front->mTextureHost->NumCompositableRefs() >= 0) {
@ -335,6 +325,19 @@ void RemoteTextureMap::PushTexture(
owner->mUsingTextureDataHolders.pop_front();
}
}
while (!owner->mReleasingTextureDataHolders.empty()) {
auto& front = owner->mReleasingTextureDataHolders.front();
// Recycle SharedTexture
if (front->mResourceWrapper) {
owner->mRecycledSharedTextures.push(std::move(front->mResourceWrapper));
}
// Recycle BufferTextureData
if (!(front->mTextureHost->GetFlags() & TextureFlags::DUMMY_TEXTURE) &&
(front->mTextureData && front->mTextureData->AsBufferTextureData())) {
owner->mRecycledTextures.push(std::move(front->mTextureData));
}
owner->mReleasingTextureDataHolders.pop_front();
}
}
const auto info = RemoteTextureInfo(aTextureId, aOwnerId, aForPid);
@ -445,8 +448,7 @@ void RemoteTextureMap::KeepTextureDataAliveForTextureHostIfNecessary(
// SharedResourceWrapper/TextureData alive while the TextureHost is alive.
if (holder->mTextureHost &&
holder->mTextureHost->NumCompositableRefs() >= 0) {
RefPtr<nsISerialEventTarget> eventTarget =
MessageLoop::current()->SerialEventTarget();
RefPtr<nsISerialEventTarget> eventTarget = GetCurrentSerialEventTarget();
RefPtr<Runnable> runnable = NS_NewRunnableFunction(
"RemoteTextureMap::UnregisterTextureOwner::Runnable",
[data = std::move(holder->mTextureData),
@ -511,6 +513,9 @@ void RemoteTextureMap::UnregisterTextureOwner(
KeepTextureDataAliveForTextureHostIfNecessary(
lock, it->second->mUsingTextureDataHolders);
KeepTextureDataAliveForTextureHostIfNecessary(
lock, it->second->mReleasingTextureDataHolders);
releasingOwner = std::move(it->second);
mTextureOwners.erase(it);
@ -577,6 +582,9 @@ void RemoteTextureMap::UnregisterTextureOwners(
KeepTextureDataAliveForTextureHostIfNecessary(
lock, it->second->mUsingTextureDataHolders);
KeepTextureDataAliveForTextureHostIfNecessary(
lock, it->second->mReleasingTextureDataHolders);
releasingOwners.push_back(std::move(it->second));
mTextureOwners.erase(it);
}
@ -657,6 +665,19 @@ void RemoteTextureMap::UpdateTexture(const MonitorAutoLock& aProofOfLock,
UniquePtr<TextureDataHolder> holder = std::move(front);
aOwner->mWaitingTextureDataHolders.pop_front();
// If there are textures not being used by the compositor that will be
// obsoleted by this new texture, then queue them for removal later on
// the creating thread.
while (!aOwner->mUsingTextureDataHolders.empty()) {
auto& back = aOwner->mUsingTextureDataHolders.back();
if (back->mTextureHost &&
back->mTextureHost->NumCompositableRefs() == 0) {
aOwner->mReleasingTextureDataHolders.push_back(std::move(back));
aOwner->mUsingTextureDataHolders.pop_back();
continue;
}
break;
}
aOwner->mUsingTextureDataHolders.push_back(std::move(holder));
}
}
@ -696,7 +717,8 @@ RemoteTextureMap::GetAllRenderingReadyCallbacks(
bool RemoteTextureMap::GetRemoteTextureForDisplayList(
RemoteTextureHostWrapper* aTextureHostWrapper,
std::function<void(const RemoteTextureInfo&)>&& aReadyCallback) {
std::function<void(const RemoteTextureInfo&)>&& aReadyCallback,
bool aWaitForRemoteTextureOwner) {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
MOZ_ASSERT(aTextureHostWrapper);
@ -714,8 +736,23 @@ bool RemoteTextureMap::GetRemoteTextureForDisplayList(
MonitorAutoLock lock(mMonitor);
auto* owner = GetTextureOwner(lock, ownerId, forPid);
if (!owner) {
return false;
// If there is no texture owner yet, then we might need to wait for one to
// be created, if allowed. If so, we must also wait for an initial texture
// host to be created so we can use it.
if (!owner || (aWaitForRemoteTextureOwner && !owner->mLatestTextureHost &&
owner->mWaitingTextureDataHolders.empty())) {
if (!aWaitForRemoteTextureOwner) {
return false;
}
const TimeDuration timeout = TimeDuration::FromMilliseconds(10000);
while (!owner || (!owner->mLatestTextureHost &&
owner->mWaitingTextureDataHolders.empty())) {
CVStatus status = mMonitor.Wait(timeout);
if (status == CVStatus::Timeout) {
return false;
}
owner = GetTextureOwner(lock, ownerId, forPid);
}
}
UpdateTexture(lock, owner, textureId);

Просмотреть файл

@ -213,7 +213,8 @@ class RemoteTextureMap {
// return true when aReadyCallback will be called.
bool GetRemoteTextureForDisplayList(
RemoteTextureHostWrapper* aTextureHostWrapper,
std::function<void(const RemoteTextureInfo&)>&& aReadyCallback);
std::function<void(const RemoteTextureInfo&)>&& aReadyCallback,
bool aWaitForRemoteTextureOwner = false);
// Get ExternalImageId of remote texture for WebRender rendering.
wr::MaybeExternalImageId GetExternalImageIdOfRemoteTexture(
@ -297,6 +298,7 @@ class RemoteTextureMap {
std::deque<UniquePtr<TextureDataHolder>> mWaitingTextureDataHolders;
// Holds TextureDataHolders that are used for building wr display list.
std::deque<UniquePtr<TextureDataHolder>> mUsingTextureDataHolders;
std::deque<UniquePtr<TextureDataHolder>> mReleasingTextureDataHolders;
// Holds async RemoteTexture ready callbacks.
std::deque<UniquePtr<RenderingReadyCallbackHolder>>
mRenderingReadyCallbackHolders;

Просмотреть файл

@ -318,6 +318,36 @@ static bool ShouldRemoteTextureType(TextureType aTextureType,
}
}
/* static */
TextureData* TextureData::Create(TextureType aTextureType,
gfx::SurfaceFormat aFormat,
const gfx::IntSize& aSize,
TextureAllocationFlags aAllocFlags,
gfx::BackendType aBackendType) {
switch (aTextureType) {
#ifdef XP_WIN
case TextureType::D3D11:
return D3D11TextureData::Create(aSize, aFormat, aAllocFlags);
#endif
#ifdef MOZ_WIDGET_GTK
case TextureType::DMABUF:
return DMABUFTextureData::Create(aSize, aFormat, aBackendType);
#endif
#ifdef XP_MACOSX
case TextureType::MacIOSurface:
return MacIOSurfaceTextureData::Create(aSize, aFormat, aBackendType);
#endif
#ifdef MOZ_WIDGET_ANDROID
case TextureType::AndroidNativeWindow:
return AndroidNativeWindowTextureData::Create(aSize, aFormat);
#endif
default:
return nullptr;
}
}
/* static */
TextureData* TextureData::Create(TextureForwarder* aAllocator,
gfx::SurfaceFormat aFormat, gfx::IntSize aSize,
@ -328,45 +358,33 @@ TextureData* TextureData::Create(TextureForwarder* aAllocator,
TextureType textureType =
GetTextureType(aFormat, aSize, aKnowsCompositor, aSelector, aAllocFlags);
if (ShouldRemoteTextureType(textureType, aSelector)) {
if ((aAllocFlags & ALLOC_FORCE_REMOTE) ||
ShouldRemoteTextureType(textureType, aSelector)) {
RefPtr<CanvasChild> canvasChild = aAllocator->GetCanvasChild();
if (canvasChild) {
return new RecordedTextureData(canvasChild.forget(), aSize, aFormat,
textureType);
}
if (aAllocFlags & ALLOC_FORCE_REMOTE) {
// If we must be remote, but there is no canvas child, then falling back
// is not possible.
return nullptr;
}
// We don't have a CanvasChild, but are supposed to be remote.
// Fall back to software.
textureType = TextureType::Unknown;
}
gfx::BackendType moz2DBackend = gfx::BackendType::NONE;
#if defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
gfx::BackendType moz2DBackend = BackendTypeForBackendSelector(
moz2DBackend = BackendTypeForBackendSelector(
aKnowsCompositor->GetCompositorBackendType(), aSelector);
#endif
switch (textureType) {
#ifdef XP_WIN
case TextureType::D3D11:
return D3D11TextureData::Create(aSize, aFormat, aAllocFlags);
#endif
#ifdef MOZ_WIDGET_GTK
case TextureType::DMABUF:
return DMABUFTextureData::Create(aSize, aFormat, moz2DBackend);
#endif
#ifdef XP_MACOSX
case TextureType::MacIOSurface:
return MacIOSurfaceTextureData::Create(aSize, aFormat, moz2DBackend);
#endif
#ifdef MOZ_WIDGET_ANDROID
case TextureType::AndroidNativeWindow:
return AndroidNativeWindowTextureData::Create(aSize, aFormat);
#endif
default:
return nullptr;
}
return TextureData::Create(textureType, aFormat, aSize, aAllocFlags,
moz2DBackend);
}
/* static */
@ -515,6 +533,7 @@ void TextureClient::Destroy() {
}
mBorrowedDrawTarget = nullptr;
mBorrowedSnapshot = false;
mReadLock = nullptr;
RefPtr<TextureChild> actor = mActor;
@ -670,6 +689,7 @@ void TextureClient::Unlock() {
mBorrowedDrawTarget = nullptr;
}
mBorrowedSnapshot = false;
if (mOpenMode & OpenMode::OPEN_WRITE) {
mUpdated = true;
@ -806,6 +826,7 @@ void TextureClient::EndDraw() {
MOZ_ASSERT(mBorrowedDrawTarget->refCount() <= mExpectedDtRefs);
mBorrowedDrawTarget = nullptr;
mBorrowedSnapshot = false;
mData->EndDraw();
}
@ -813,7 +834,9 @@ already_AddRefed<gfx::SourceSurface> TextureClient::BorrowSnapshot() {
MOZ_ASSERT(mIsLocked);
RefPtr<gfx::SourceSurface> surface = mData->BorrowSnapshot();
if (!surface) {
if (surface) {
mBorrowedSnapshot = true;
} else {
RefPtr<gfx::DrawTarget> drawTarget = BorrowDrawTarget();
if (!drawTarget) {
return nullptr;
@ -824,6 +847,15 @@ already_AddRefed<gfx::SourceSurface> TextureClient::BorrowSnapshot() {
return surface.forget();
}
void TextureClient::ReturnSnapshot(
already_AddRefed<gfx::SourceSurface> aSnapshot) {
RefPtr<gfx::SourceSurface> snapshot = aSnapshot;
if (mBorrowedSnapshot) {
mData->ReturnSnapshot(snapshot.forget());
mBorrowedSnapshot = false;
}
}
bool TextureClient::BorrowMappedData(MappedTextureData& aMap) {
MOZ_ASSERT(IsValid());
@ -1160,6 +1192,10 @@ already_AddRefed<TextureClient> TextureClient::CreateForDrawing(
if (data) {
return MakeAndAddRef<TextureClient>(data, aTextureFlags, aAllocator);
}
if (aAllocFlags & ALLOC_FORCE_REMOTE) {
// If we must be remote, but allocation failed, then don't fall back.
return nullptr;
}
// Can't do any better than a buffer texture client.
return TextureClient::CreateForRawBufferAccess(aAllocator, aFormat, aSize,

Просмотреть файл

@ -70,6 +70,7 @@ class SharedSurfaceTextureData;
class TextureClientPool;
#endif
class TextureForwarder;
struct RemoteTextureOwnerId;
/**
* TextureClient is the abstraction that allows us to share data between the
@ -99,6 +100,9 @@ enum TextureAllocationFlags {
// Do not use an accelerated texture type.
ALLOC_DO_NOT_ACCELERATE = 1 << 8,
// Force allocation of remote/recorded texture, or fail if not possible.
ALLOC_FORCE_REMOTE = 1 << 9,
};
enum class BackendSelector { Content, Canvas };
@ -223,6 +227,10 @@ class TextureData {
canConcurrentlyReadLock(true) {}
};
static TextureData* Create(
TextureType aTextureType, gfx::SurfaceFormat aFormat,
const gfx::IntSize& aSize, TextureAllocationFlags aAllocFlags,
gfx::BackendType aBackendType = gfx::BackendType::NONE);
static TextureData* Create(TextureForwarder* aAllocator,
gfx::SurfaceFormat aFormat, gfx::IntSize aSize,
KnowsCompositor* aKnowsCompositor,
@ -255,6 +263,8 @@ class TextureData {
return nullptr;
}
virtual void ReturnSnapshot(already_AddRefed<gfx::SourceSurface> aSnapshot) {}
virtual bool BorrowMappedData(MappedTextureData&) { return false; }
virtual bool BorrowMappedYCbCrData(MappedYCbCrTextureData&) { return false; }
@ -312,6 +322,10 @@ class TextureData {
return mozilla::ipc::FileDescriptor();
}
virtual void SetRemoteTextureOwnerId(RemoteTextureOwnerId) {}
virtual bool RequiresRefresh() const { return false; }
protected:
MOZ_COUNTED_DEFAULT_CTOR(TextureData)
};
@ -447,6 +461,8 @@ class TextureClient : public AtomicRefCountedWithFinalize<TextureClient> {
already_AddRefed<gfx::SourceSurface> BorrowSnapshot();
void ReturnSnapshot(already_AddRefed<gfx::SourceSurface> aSnapshot);
/**
* Similar to BorrowDrawTarget but provides direct access to the texture's
* bits instead of a DrawTarget.
@ -703,6 +719,7 @@ class TextureClient : public AtomicRefCountedWithFinalize<TextureClient> {
TextureData* mData;
RefPtr<gfx::DrawTarget> mBorrowedDrawTarget;
bool mBorrowedSnapshot = false;
TextureFlags mFlags;

Просмотреть файл

@ -30,6 +30,7 @@ RecordedTextureData::~RecordedTextureData() {
// We need the translator to drop its reference for the DrawTarget first,
// because the TextureData might need to destroy its DrawTarget within a lock.
mDT = nullptr;
mCanvasChild->CleanupTexture(mTextureId);
mCanvasChild->RecordEvent(RecordedTextureDestruction(mTextureId));
}
@ -40,15 +41,25 @@ void RecordedTextureData::FillInfo(TextureData::Info& aInfo) const {
aInfo.hasSynchronization = true;
}
void RecordedTextureData::SetRemoteTextureOwnerId(
RemoteTextureOwnerId aRemoteTextureOwnerId) {
mRemoteTextureOwnerId = aRemoteTextureOwnerId;
}
bool RecordedTextureData::Lock(OpenMode aMode) {
if (!mCanvasChild->EnsureBeginTransaction()) {
return false;
}
if (mRemoteTextureOwnerId.IsValid()) {
mLastRemoteTextureId = RemoteTextureId::GetNext();
}
if (!mDT) {
mTextureId = sNextRecordedTextureId++;
mCanvasChild->RecordEvent(RecordedNextTextureId(mTextureId));
mDT = mCanvasChild->CreateDrawTarget(mSize, mFormat);
mCanvasChild->RecordEvent(
RecordedNextTextureId(mTextureId, mRemoteTextureOwnerId));
mDT = mCanvasChild->CreateDrawTarget(mTextureId, mSize, mFormat);
if (!mDT) {
return false;
}
@ -59,7 +70,8 @@ bool RecordedTextureData::Lock(OpenMode aMode) {
return true;
}
mCanvasChild->RecordEvent(RecordedTextureLock(mTextureId, aMode));
mCanvasChild->RecordEvent(
RecordedTextureLock(mTextureId, aMode, mLastRemoteTextureId));
if (aMode & OpenMode::OPEN_WRITE) {
mCanvasChild->OnTextureWriteLock();
}
@ -75,12 +87,18 @@ void RecordedTextureData::Unlock() {
mCanvasChild->RecordEvent(RecordedCacheDataSurface(mSnapshot.get()));
}
mCanvasChild->RecordEvent(RecordedTextureUnlock(mTextureId));
mCanvasChild->RecordEvent(
RecordedTextureUnlock(mTextureId, mLastRemoteTextureId));
mLockedMode = OpenMode::OPEN_NONE;
}
already_AddRefed<gfx::DrawTarget> RecordedTextureData::BorrowDrawTarget() {
mSnapshot = nullptr;
if (RefPtr<gfx::SourceSurface> wrapper = do_AddRef(mSnapshotWrapper)) {
mCanvasChild->DetachSurface(wrapper);
mSnapshotWrapper = nullptr;
}
return do_AddRef(mDT);
}
@ -95,23 +113,39 @@ void RecordedTextureData::EndDraw() {
}
already_AddRefed<gfx::SourceSurface> RecordedTextureData::BorrowSnapshot() {
if (RefPtr<gfx::SourceSurface> wrapper = do_AddRef(mSnapshotWrapper)) {
return wrapper.forget();
}
// There are some failure scenarios where we have no DrawTarget and
// BorrowSnapshot is called in an attempt to copy to a new texture.
if (!mDT) {
return nullptr;
}
if (mSnapshot) {
return mCanvasChild->WrapSurface(mSnapshot);
}
RefPtr<gfx::SourceSurface> wrapper = mCanvasChild->WrapSurface(
mSnapshot ? mSnapshot : mDT->Snapshot(), mTextureId);
mSnapshotWrapper = wrapper;
return wrapper.forget();
}
return mCanvasChild->WrapSurface(mDT->Snapshot());
void RecordedTextureData::ReturnSnapshot(
already_AddRefed<gfx::SourceSurface> aSnapshot) {
RefPtr<gfx::SourceSurface> snapshot = aSnapshot;
if (RefPtr<gfx::SourceSurface> wrapper = do_AddRef(mSnapshotWrapper)) {
mCanvasChild->DetachSurface(wrapper);
}
}
void RecordedTextureData::Deallocate(LayersIPCChannel* aAllocator) {}
bool RecordedTextureData::Serialize(SurfaceDescriptor& aDescriptor) {
aDescriptor = SurfaceDescriptorRecorded(mTextureId);
if (mRemoteTextureOwnerId.IsValid()) {
aDescriptor = SurfaceDescriptorRemoteTexture(mLastRemoteTextureId,
mRemoteTextureOwnerId);
} else {
aDescriptor = SurfaceDescriptorRecorded(mTextureId);
}
return true;
}
@ -125,5 +159,9 @@ TextureFlags RecordedTextureData::GetTextureFlags() const {
return TextureFlags::WAIT_HOST_USAGE_END;
}
bool RecordedTextureData::RequiresRefresh() const {
return mCanvasChild->RequiresRefresh(mTextureId);
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -32,6 +32,8 @@ class RecordedTextureData final : public TextureData {
already_AddRefed<gfx::SourceSurface> BorrowSnapshot() final;
void ReturnSnapshot(already_AddRefed<gfx::SourceSurface> aSnapshot) final;
void Deallocate(LayersIPCChannel* aAllocator) final;
bool Serialize(SurfaceDescriptor& aDescriptor) final;
@ -40,6 +42,11 @@ class RecordedTextureData final : public TextureData {
TextureFlags GetTextureFlags() const final;
void SetRemoteTextureOwnerId(
RemoteTextureOwnerId aRemoteTextureOwnerId) final;
bool RequiresRefresh() const final;
private:
DISALLOW_COPY_AND_ASSIGN(RecordedTextureData);
@ -51,7 +58,10 @@ class RecordedTextureData final : public TextureData {
gfx::SurfaceFormat mFormat;
RefPtr<gfx::DrawTarget> mDT;
RefPtr<gfx::SourceSurface> mSnapshot;
ThreadSafeWeakPtr<gfx::SourceSurface> mSnapshotWrapper;
OpenMode mLockedMode;
layers::RemoteTextureId mLastRemoteTextureId;
layers::RemoteTextureOwnerId mRemoteTextureOwnerId;
};
} // namespace layers

Просмотреть файл

@ -15,6 +15,7 @@
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/ipc/ProcessChild.h"
#include "mozilla/layers/CanvasDrawEventRecorder.h"
#include "mozilla/layers/ImageDataSerializer.h"
#include "mozilla/layers/SourceSurfaceSharedData.h"
#include "mozilla/Maybe.h"
#include "nsIObserverService.h"
@ -30,22 +31,22 @@ class RecorderHelpers final : public CanvasDrawEventRecorder::Helpers {
~RecorderHelpers() override = default;
bool InitTranslator(const TextureType& aTextureType, Handle&& aReadHandle,
nsTArray<Handle>&& aBufferHandles,
const uint64_t& aBufferSize,
bool InitTranslator(TextureType aTextureType, gfx::BackendType aBackendType,
Handle&& aReadHandle, nsTArray<Handle>&& aBufferHandles,
uint64_t aBufferSize,
CrossProcessSemaphoreHandle&& aReaderSem,
CrossProcessSemaphoreHandle&& aWriterSem,
const bool& aUseIPDLThread) override {
bool aUseIPDLThread) override {
if (!mCanvasChild) {
return false;
}
return mCanvasChild->SendInitTranslator(
aTextureType, std::move(aReadHandle), std::move(aBufferHandles),
aBufferSize, std::move(aReaderSem), std::move(aWriterSem),
aUseIPDLThread);
aTextureType, aBackendType, std::move(aReadHandle),
std::move(aBufferHandles), aBufferSize, std::move(aReaderSem),
std::move(aWriterSem), aUseIPDLThread);
}
bool AddBuffer(Handle&& aBufferHandle, const uint64_t& aBufferSize) override {
bool AddBuffer(Handle&& aBufferHandle, uint64_t aBufferSize) override {
if (!mCanvasChild) {
return false;
}
@ -75,10 +76,11 @@ class SourceSurfaceCanvasRecording final : public gfx::SourceSurface {
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceCanvasRecording, final)
SourceSurfaceCanvasRecording(
const RefPtr<gfx::SourceSurface>& aRecordedSuface,
int64_t aTextureId, const RefPtr<gfx::SourceSurface>& aRecordedSuface,
CanvasChild* aCanvasChild,
const RefPtr<CanvasDrawEventRecorder>& aRecorder)
: mRecordedSurface(aRecordedSuface),
: mTextureId(aTextureId),
mRecordedSurface(aRecordedSuface),
mCanvasChild(aCanvasChild),
mRecorder(aRecorder) {
// It's important that AddStoredObject is called first because that will
@ -119,11 +121,14 @@ class SourceSurfaceCanvasRecording final : public gfx::SourceSurface {
return do_AddRef(mDataSourceSurface);
}
void DrawTargetWillChange() { mDetached = true; }
private:
void EnsureDataSurfaceOnMainThread() {
// The data can only be retrieved on the main thread.
if (!mDataSourceSurface && NS_IsMainThread()) {
mDataSourceSurface = mCanvasChild->GetDataSurface(mRecordedSurface);
mDataSourceSurface =
mCanvasChild->GetDataSurface(mTextureId, mRecordedSurface, mDetached);
}
}
@ -141,10 +146,12 @@ class SourceSurfaceCanvasRecording final : public gfx::SourceSurface {
aRecorder = nullptr;
}
int64_t mTextureId;
RefPtr<gfx::SourceSurface> mRecordedSurface;
RefPtr<CanvasChild> mCanvasChild;
RefPtr<CanvasDrawEventRecorder> mRecorder;
RefPtr<gfx::DataSourceSurface> mDataSourceSurface;
bool mDetached = false;
};
CanvasChild::CanvasChild() = default;
@ -176,11 +183,21 @@ ipc::IPCResult CanvasChild::RecvDeactivate() {
return IPC_OK();
}
ipc::IPCResult CanvasChild::RecvBlockCanvas() {
if (auto* cm = gfx::CanvasManagerChild::Get()) {
cm->BlockCanvas();
}
return IPC_OK();
}
void CanvasChild::EnsureRecorder(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
TextureType aTextureType) {
if (!mRecorder) {
gfx::BackendType backendType =
gfxPlatform::GetPlatform()->GetPreferredCanvasBackend();
auto recorder = MakeRefPtr<CanvasDrawEventRecorder>();
if (!recorder->Init(aTextureType, MakeUnique<RecorderHelpers>(this))) {
if (!recorder->Init(aTextureType, backendType,
MakeUnique<RecorderHelpers>(this))) {
return;
}
@ -280,7 +297,7 @@ bool CanvasChild::ShouldBeCleanedUp() const {
}
already_AddRefed<gfx::DrawTarget> CanvasChild::CreateDrawTarget(
gfx::IntSize aSize, gfx::SurfaceFormat aFormat) {
int64_t aTextureId, gfx::IntSize aSize, gfx::SurfaceFormat aFormat) {
if (!mRecorder) {
return nullptr;
}
@ -290,14 +307,19 @@ already_AddRefed<gfx::DrawTarget> CanvasChild::CreateDrawTarget(
RefPtr<gfx::DrawTarget> dt = MakeAndAddRef<gfx::DrawTargetRecording>(
mRecorder, dummyDt, gfx::IntRect(gfx::IntPoint(0, 0), aSize));
mTextureInfo.insert({aTextureId, {}});
return dt.forget();
}
bool CanvasChild::EnsureDataSurfaceShmem(gfx::IntSize aSize,
gfx::SurfaceFormat aFormat) {
size_t dataFormatWidth = aSize.width * BytesPerPixel(aFormat);
size_t sizeRequired =
ipc::SharedMemory::PageAlignedSize(dataFormatWidth * aSize.height);
ImageDataSerializer::ComputeRGBBufferSize(aSize, aFormat);
if (!sizeRequired) {
return false;
}
sizeRequired = ipc::SharedMemory::PageAlignedSize(sizeRequired);
if (!mDataSurfaceShmemAvailable || mDataSurfaceShmem->Size() < sizeRequired) {
RecordEvent(RecordedPauseTranslation());
@ -338,7 +360,7 @@ int64_t CanvasChild::CreateCheckpoint() {
}
already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface(
const gfx::SourceSurface* aSurface) {
int64_t aTextureId, const gfx::SourceSurface* aSurface, bool aDetached) {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aSurface);
@ -354,6 +376,28 @@ already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface(
return nullptr;
}
// Shmem is only valid if the surface is the latest snapshot (not detached).
if (!aDetached) {
// If there is a shmem associated with this snapshot id, then we want to try
// use that directly without having to allocate a new shmem for retrieval.
auto it = mTextureInfo.find(aTextureId);
if (it != mTextureInfo.end() && it->second.mSnapshotShmem) {
const auto shmemPtr =
reinterpret_cast<uint8_t*>(it->second.mSnapshotShmem->memory());
MOZ_ASSERT(shmemPtr);
mRecorder->RecordEvent(RecordedPrepareShmem(aTextureId));
auto checkpoint = CreateCheckpoint();
mRecorder->WaitForCheckpoint(checkpoint);
gfx::IntSize size = aSurface->GetSize();
gfx::SurfaceFormat format = aSurface->GetFormat();
auto stride = ImageDataSerializer::ComputeRGBStride(format, size.width);
RefPtr<gfx::DataSourceSurface> dataSurface =
gfx::Factory::CreateWrappingDataSourceSurface(shmemPtr, stride, size,
format);
return dataSurface.forget();
}
}
RecordEvent(RecordedPrepareDataForSurface(aSurface));
gfx::IntSize ssSize = aSurface->GetSize();
@ -372,11 +416,11 @@ already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface(
auto* data = static_cast<uint8_t*>(mDataSurfaceShmem->memory());
auto* closure = new DataShmemHolder{do_AddRef(mDataSurfaceShmem), this};
auto dataFormatWidth = ssSize.width * BytesPerPixel(ssFormat);
auto stride = ImageDataSerializer::ComputeRGBStride(ssFormat, ssSize.width);
RefPtr<gfx::DataSourceSurface> dataSurface =
gfx::Factory::CreateWrappingDataSourceSurface(
data, dataFormatWidth, ssSize, ssFormat,
data, stride, ssSize, ssFormat,
[](void* aClosure) {
auto* shmemHolder = static_cast<DataShmemHolder*>(aClosure);
shmemHolder->canvasChild->ReturnDataSurfaceShmem(
@ -390,12 +434,13 @@ already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface(
}
already_AddRefed<gfx::SourceSurface> CanvasChild::WrapSurface(
const RefPtr<gfx::SourceSurface>& aSurface) {
const RefPtr<gfx::SourceSurface>& aSurface, int64_t aTextureId) {
if (!aSurface) {
return nullptr;
}
return MakeAndAddRef<SourceSurfaceCanvasRecording>(aSurface, this, mRecorder);
return MakeAndAddRef<SourceSurfaceCanvasRecording>(aTextureId, aSurface, this,
mRecorder);
}
void CanvasChild::ReturnDataSurfaceShmem(
@ -408,5 +453,52 @@ void CanvasChild::ReturnDataSurfaceShmem(
}
}
void CanvasChild::DetachSurface(const RefPtr<gfx::SourceSurface>& aSurface) {
if (auto* surface =
static_cast<SourceSurfaceCanvasRecording*>(aSurface.get())) {
surface->DrawTargetWillChange();
}
}
ipc::IPCResult CanvasChild::RecvNotifyRequiresRefresh(int64_t aTextureId) {
auto it = mTextureInfo.find(aTextureId);
if (it != mTextureInfo.end()) {
it->second.mRequiresRefresh = true;
}
return IPC_OK();
}
bool CanvasChild::RequiresRefresh(int64_t aTextureId) const {
auto it = mTextureInfo.find(aTextureId);
if (it != mTextureInfo.end()) {
return it->second.mRequiresRefresh;
}
return false;
}
ipc::IPCResult CanvasChild::RecvSnapshotShmem(
int64_t aTextureId, Handle&& aShmemHandle, uint32_t aShmemSize,
SnapshotShmemResolver&& aResolve) {
auto it = mTextureInfo.find(aTextureId);
if (it != mTextureInfo.end()) {
auto shmem = MakeRefPtr<ipc::SharedMemoryBasic>();
if (NS_WARN_IF(!shmem->SetHandle(std::move(aShmemHandle),
ipc::SharedMemory::RightsReadOnly)) ||
NS_WARN_IF(!shmem->Map(aShmemSize))) {
shmem = nullptr;
} else {
it->second.mSnapshotShmem = std::move(shmem);
}
aResolve(true);
} else {
aResolve(false);
}
return IPC_OK();
}
void CanvasChild::CleanupTexture(int64_t aTextureId) {
mTextureInfo.erase(aTextureId);
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -42,6 +42,14 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr {
ipc::IPCResult RecvDeactivate();
ipc::IPCResult RecvBlockCanvas();
ipc::IPCResult RecvNotifyRequiresRefresh(int64_t aTextureId);
ipc::IPCResult RecvSnapshotShmem(int64_t aTextureId, Handle&& aShmemHandle,
uint32_t aShmemSize,
SnapshotShmemResolver&& aResolve);
/**
* Ensures that the DrawEventRecorder has been created.
*
@ -92,12 +100,13 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr {
/**
* Create a DrawTargetRecording for a canvas texture.
* @param aTextureId the id of the new texture
* @param aSize size for the DrawTarget
* @param aFormat SurfaceFormat for the DrawTarget
* @returns newly created DrawTargetRecording
*/
already_AddRefed<gfx::DrawTarget> CreateDrawTarget(
gfx::IntSize aSize, gfx::SurfaceFormat aFormat);
int64_t aTextureId, gfx::IntSize aSize, gfx::SurfaceFormat aFormat);
/**
* Record an event for processing by the CanvasParent's CanvasTranslator.
@ -111,21 +120,33 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr {
* Wrap the given surface, so that we can provide a DataSourceSurface if
* required.
* @param aSurface the SourceSurface to wrap
* @param aTextureId the texture id of the source TextureData
* @returns a SourceSurface that can provide a DataSourceSurface if required
*/
already_AddRefed<gfx::SourceSurface> WrapSurface(
const RefPtr<gfx::SourceSurface>& aSurface);
const RefPtr<gfx::SourceSurface>& aSurface, int64_t aTextureId);
/**
* The DrawTargetRecording is about to change, so detach the old snapshot.
*/
void DetachSurface(const RefPtr<gfx::SourceSurface>& aSurface);
/**
* Get DataSourceSurface from the translated equivalent version of aSurface in
* the GPU process.
* @param aTextureId the source TextureData to read from
* @param aSurface the SourceSurface in this process for which we need a
* DataSourceSurface
* @param aDetached whether the surface is old
* @returns a DataSourceSurface created from data for aSurface retrieve from
* GPU process
*/
already_AddRefed<gfx::DataSourceSurface> GetDataSurface(
const gfx::SourceSurface* aSurface);
int64_t aTextureId, const gfx::SourceSurface* aSurface, bool aDetached);
bool RequiresRefresh(int64_t aTextureId) const;
void CleanupTexture(int64_t aTextureId);
protected:
void ActorDestroy(ActorDestroyReason aWhy) final;
@ -153,6 +174,11 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr {
int64_t mLastWriteLockCheckpoint = 0;
uint32_t mTransactionsSinceGetDataSurface = kCacheDataSurfaceThreshold;
std::vector<RefPtr<gfx::SourceSurface>> mLastTransactionExternalSurfaces;
struct TextureInfo {
RefPtr<mozilla::ipc::SharedMemoryBasic> mSnapshotShmem;
bool mRequiresRefresh = false;
};
std::unordered_map<int64_t, TextureInfo> mTextureInfo;
bool mIsInTransaction = false;
bool mHasOutstandingWriteLock = false;
bool mDormant = false;

Просмотреть файл

@ -10,17 +10,21 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/CanvasManagerParent.h"
#include "mozilla/gfx/CanvasRenderThread.h"
#include "mozilla/gfx/DrawTargetWebgl.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/GPUParent.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/layers/BufferTexture.h"
#include "mozilla/layers/CanvasTranslator.h"
#include "mozilla/layers/ImageDataSerializer.h"
#include "mozilla/layers/SharedSurfacesParent.h"
#include "mozilla/layers/TextureClient.h"
#include "mozilla/StaticPrefs_gfx.h"
#include "mozilla/SyncRunnable.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/Telemetry.h"
#include "GLContext.h"
#include "RecordedCanvasEventImpl.h"
#if defined(XP_WIN)
@ -32,6 +36,7 @@ namespace mozilla {
namespace layers {
TextureData* CanvasTranslator::CreateTextureData(TextureType aTextureType,
gfx::BackendType aBackendType,
const gfx::IntSize& aSize,
gfx::SurfaceFormat aFormat) {
TextureData* textureData = nullptr;
@ -43,8 +48,16 @@ TextureData* CanvasTranslator::CreateTextureData(TextureType aTextureType,
break;
}
#endif
case TextureType::Unknown:
textureData = BufferTextureData::Create(
aSize, aFormat, gfx::BackendType::SKIA, LayersBackend::LAYERS_WR,
TextureFlags::DEALLOCATE_CLIENT | TextureFlags::REMOTE_TEXTURE,
ALLOC_CLEAR_BUFFER, nullptr);
break;
default:
MOZ_CRASH("Unsupported TextureType for CanvasTranslator.");
textureData = TextureData::Create(aTextureType, aFormat, aSize,
ALLOC_CLEAR_BUFFER, aBackendType);
break;
}
return textureData;
@ -64,12 +77,7 @@ CanvasTranslator::CanvasTranslator(
Telemetry::ScalarAdd(Telemetry::ScalarID::GFX_CANVAS_REMOTE_ACTIVATED, 1);
}
CanvasTranslator::~CanvasTranslator() {
// The textures need to be the last thing holding their DrawTargets, so that
// they can destroy them within a lock.
mDrawTargets.Clear();
mBaseDT = nullptr;
}
CanvasTranslator::~CanvasTranslator() = default;
void CanvasTranslator::DispatchToTaskQueue(
already_AddRefed<nsIRunnable> aRunnable) {
@ -102,16 +110,30 @@ static bool CreateAndMapShmem(RefPtr<ipc::SharedMemoryBasic>& aShmem,
return true;
}
bool CanvasTranslator::EnsureSharedContextWebgl() {
if (!mSharedContext || mSharedContext->IsContextLost()) {
mSharedContext = gfx::SharedContextWebgl::Create();
if (!mSharedContext || mSharedContext->IsContextLost()) {
mSharedContext = nullptr;
BlockCanvas();
return false;
}
}
return true;
}
mozilla::ipc::IPCResult CanvasTranslator::RecvInitTranslator(
const TextureType& aTextureType, Handle&& aReadHandle,
nsTArray<Handle>&& aBufferHandles, uint64_t aBufferSize,
CrossProcessSemaphoreHandle&& aReaderSem,
TextureType aTextureType, gfx::BackendType aBackendType,
Handle&& aReadHandle, nsTArray<Handle>&& aBufferHandles,
uint64_t aBufferSize, CrossProcessSemaphoreHandle&& aReaderSem,
CrossProcessSemaphoreHandle&& aWriterSem, bool aUseIPDLThread) {
if (mHeaderShmem) {
return IPC_FAIL(this, "RecvInitTranslator called twice.");
}
mTextureType = aTextureType;
mBackendType = aBackendType;
mOtherPid = OtherPid();
mHeaderShmem = MakeAndAddRef<ipc::SharedMemoryBasic>();
if (!CreateAndMapShmem(mHeaderShmem, std::move(aReadHandle),
@ -127,12 +149,15 @@ mozilla::ipc::IPCResult CanvasTranslator::RecvInitTranslator(
mReaderSemaphore.reset(CrossProcessSemaphore::Create(std::move(aReaderSem)));
mReaderSemaphore->CloseHandle();
#if defined(XP_WIN)
if (!CheckForFreshCanvasDevice(__LINE__)) {
gfxCriticalNote << "GFX: CanvasTranslator failed to get device";
return IPC_OK();
}
#endif
if (gfx::gfxVars::UseAcceleratedCanvas2D() && !EnsureSharedContextWebgl()) {
gfxCriticalNote
<< "GFX: CanvasTranslator failed creating WebGL shared context";
}
if (!aUseIPDLThread) {
mTranslationTaskQueue = gfx::CanvasRenderThread::CreateWorkerTaskQueue();
@ -269,24 +294,29 @@ void CanvasTranslator::GetDataSurface(uint64_t aSurfaceRef) {
auto dstSize = surface->GetSize();
auto srcSize = map->GetSurface()->GetSize();
int32_t dataFormatWidth = dstSize.width * BytesPerPixel(surface->GetFormat());
gfx::SurfaceFormat format = surface->GetFormat();
int32_t bpp = BytesPerPixel(format);
int32_t dataFormatWidth = dstSize.width * bpp;
int32_t srcStride = map->GetStride();
if (dataFormatWidth > srcStride || srcSize != dstSize) {
return;
}
auto requiredSize = dataFormatWidth * dstSize.height;
int32_t dstStride =
ImageDataSerializer::ComputeRGBStride(format, dstSize.width);
auto requiredSize =
ImageDataSerializer::ComputeRGBBufferSize(dstSize, format);
if (requiredSize <= 0 || size_t(requiredSize) > mDataSurfaceShmem->Size()) {
return;
}
char* dst = static_cast<char*>(mDataSurfaceShmem->memory());
const char* src = reinterpret_cast<char*>(map->GetData());
const char* endSrc = src + (srcSize.height * srcStride);
uint8_t* dst = static_cast<uint8_t*>(mDataSurfaceShmem->memory());
const uint8_t* src = map->GetData();
const uint8_t* endSrc = src + (srcSize.height * srcStride);
while (src < endSrc) {
memcpy(dst, src, dataFormatWidth);
src += srcStride;
dst += dataFormatWidth;
dst += dstStride;
}
}
@ -318,6 +348,9 @@ void CanvasTranslator::ActorDestroy(ActorDestroyReason why) {
void CanvasTranslator::FinishShutdown() {
MOZ_ASSERT(gfx::CanvasRenderThread::IsInCanvasRenderThread());
ClearTextureInfo();
gfx::CanvasManagerParent::RemoveReplayTextures(this);
}
@ -326,7 +359,8 @@ bool CanvasTranslator::CheckDeactivated() {
return true;
}
if (NS_WARN_IF(!gfx::gfxVars::RemoteCanvasEnabled())) {
if (NS_WARN_IF(!gfx::gfxVars::RemoteCanvasEnabled() &&
!gfx::gfxVars::UseAcceleratedCanvas2D())) {
Deactivate();
}
@ -347,18 +381,31 @@ void CanvasTranslator::Deactivate() {
&CanvasTranslator::SendDeactivate));
// Unlock all of our textures.
for (auto const& entry : mTextureDatas) {
entry.second->Unlock();
for (auto const& entry : mTextureInfo) {
if (entry.second.mTextureData) {
entry.second.mTextureData->Unlock();
}
}
// Disable remote canvas for all.
gfx::CanvasManagerParent::DisableRemoteCanvas();
}
void CanvasTranslator::BlockCanvas() {
if (mDeactivated || mBlocked) {
return;
}
mBlocked = true;
gfx::CanvasRenderThread::Dispatch(
NewRunnableMethod("CanvasTranslator::SendBlockCanvas", this,
&CanvasTranslator::SendBlockCanvas));
}
void CanvasTranslator::CheckAndSignalWriter() {
do {
switch (mHeader->writerState) {
case State::Processing:
case State::Failed:
return;
case State::AboutToWait:
// The writer is making a decision about whether to wait. So, we must
@ -442,6 +489,15 @@ bool CanvasTranslator::ReadNextEvent(EventType& aEventType) {
void CanvasTranslator::TranslateRecording() {
MOZ_ASSERT(IsInTaskQueue());
if (mSharedContext && EnsureSharedContextWebgl()) {
mSharedContext->EnterTlsScope();
}
auto exitTlsScope = MakeScopeExit([&] {
if (mSharedContext) {
mSharedContext->ExitTlsScope();
}
});
mHeader->readerState = State::Processing;
EventType eventType;
while (ReadNextEvent(eventType)) {
@ -543,25 +599,33 @@ bool CanvasTranslator::CreateReferenceTexture() {
mReferenceTextureData->Unlock();
}
mReferenceTextureData.reset(CreateTextureData(
mTextureType, gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8A8));
if (!mReferenceTextureData) {
mReferenceTextureData.reset(CreateTextureData(mTextureType, mBackendType,
gfx::IntSize(1, 1),
gfx::SurfaceFormat::B8G8R8A8));
if (!mReferenceTextureData ||
NS_WARN_IF(!mReferenceTextureData->Lock(OpenMode::OPEN_READ_WRITE))) {
mReferenceTextureData.reset();
return false;
}
mReferenceTextureData->Lock(OpenMode::OPEN_READ_WRITE);
mBaseDT = mReferenceTextureData->BorrowDrawTarget();
if (!mBaseDT) {
// We might get a null draw target due to a device failure, just return
// false so that we can recover.
return false;
}
mBackendType = mBaseDT->GetBackendType();
return true;
}
bool CanvasTranslator::CheckForFreshCanvasDevice(int aLineNumber) {
// If not on D3D11, we are not dependent on a fresh device for DT creation if
// one already exists.
if (mBaseDT && mTextureType != TextureType::D3D11) {
return false;
}
#if defined(XP_WIN)
// If a new device has already been created, use that one.
RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetCanvasDevice();
@ -601,11 +665,9 @@ bool CanvasTranslator::CheckForFreshCanvasDevice(int aLineNumber) {
Deactivate();
return false;
}
#endif
return CreateReferenceTexture();
#else
return false;
#endif
}
void CanvasTranslator::NotifyDeviceChanged() {
@ -615,29 +677,120 @@ void CanvasTranslator::NotifyDeviceChanged() {
&CanvasTranslator::SendNotifyDeviceChanged));
}
gfx::DrawTargetWebgl* CanvasTranslator::GetDrawTargetWebgl(
int64_t aTextureId) const {
auto result = mTextureInfo.find(aTextureId);
if (result != mTextureInfo.end() && result->second.mDrawTarget &&
result->second.mDrawTarget->GetBackendType() == gfx::BackendType::WEBGL) {
return static_cast<gfx::DrawTargetWebgl*>(result->second.mDrawTarget.get());
}
return nullptr;
}
void CanvasTranslator::NotifyRequiresRefresh(int64_t aTextureId,
bool aDispatch) {
if (aDispatch) {
DispatchToTaskQueue(NewRunnableMethod<int64_t, bool>(
"CanvasTranslator::NotifyRequiresRefresh", this,
&CanvasTranslator::NotifyRequiresRefresh, aTextureId, false));
return;
}
if (mTextureInfo.find(aTextureId) != mTextureInfo.end()) {
Unused << SendNotifyRequiresRefresh(aTextureId);
}
}
void CanvasTranslator::CacheSnapshotShmem(int64_t aTextureId, bool aDispatch) {
if (aDispatch) {
DispatchToTaskQueue(NewRunnableMethod<int64_t, bool>(
"CanvasTranslator::CacheSnapshotShmem", this,
&CanvasTranslator::CacheSnapshotShmem, aTextureId, false));
return;
}
if (gfx::DrawTargetWebgl* webgl = GetDrawTargetWebgl(aTextureId)) {
if (auto shmemHandle = webgl->TakeShmemHandle()) {
// Lock the DT so that it doesn't get removed while shmem is in transit.
mTextureInfo[aTextureId].mLocked++;
nsCOMPtr<nsIThread> thread =
gfx::CanvasRenderThread::GetCanvasRenderThread();
RefPtr<CanvasTranslator> translator = this;
SendSnapshotShmem(aTextureId, std::move(shmemHandle),
webgl->GetShmemSize())
->Then(
thread, __func__,
[=](bool) { translator->RemoveTexture(aTextureId); },
[=](ipc::ResponseRejectReason) {
translator->RemoveTexture(aTextureId);
});
}
}
}
void CanvasTranslator::PrepareShmem(int64_t aTextureId) {
if (gfx::DrawTargetWebgl* webgl = GetDrawTargetWebgl(aTextureId)) {
webgl->PrepareData();
}
}
already_AddRefed<gfx::DrawTarget> CanvasTranslator::CreateDrawTarget(
gfx::ReferencePtr aRefPtr, const gfx::IntSize& aSize,
gfx::SurfaceFormat aFormat) {
MOZ_DIAGNOSTIC_ASSERT(mNextTextureId >= 0, "No texture ID set");
RefPtr<gfx::DrawTarget> dt;
do {
TextureData* textureData = CreateTextureData(mTextureType, aSize, aFormat);
if (textureData) {
MOZ_DIAGNOSTIC_ASSERT(mNextTextureId >= 0, "No texture ID set");
textureData->Lock(OpenMode::OPEN_READ_WRITE);
mTextureDatas[mNextTextureId] = UniquePtr<TextureData>(textureData);
gfx::CanvasManagerParent::AddReplayTexture(this, mNextTextureId,
textureData);
dt = textureData->BorrowDrawTarget();
if (mNextRemoteTextureOwnerId.IsValid()) {
if (EnsureSharedContextWebgl()) {
mSharedContext->EnterTlsScope();
}
} while (!dt && CheckForFreshCanvasDevice(__LINE__));
if (RefPtr<gfx::DrawTargetWebgl> webgl =
gfx::DrawTargetWebgl::Create(aSize, aFormat, mSharedContext)) {
webgl->BeginFrame(gfx::IntRect());
dt = webgl.forget().downcast<gfx::DrawTarget>();
if (dt) {
TextureInfo& info = mTextureInfo[mNextTextureId];
info.mDrawTarget = dt;
info.mRemoteTextureOwnerId = mNextRemoteTextureOwnerId;
CacheSnapshotShmem(mNextTextureId);
}
}
if (!dt) {
NotifyRequiresRefresh(mNextTextureId);
}
}
if (!dt) {
do {
TextureData* textureData =
CreateTextureData(mTextureType, mBackendType, aSize, aFormat);
if (textureData) {
TextureInfo& info = mTextureInfo[mNextTextureId];
info.mTextureData = UniquePtr<TextureData>(textureData);
info.mRemoteTextureOwnerId = mNextRemoteTextureOwnerId;
if (NS_WARN_IF(!textureData->Lock(OpenMode::OPEN_READ_WRITE))) {
continue;
}
dt = textureData->BorrowDrawTarget();
}
} while (!dt && CheckForFreshCanvasDevice(__LINE__));
}
AddDrawTarget(aRefPtr, dt);
mNextTextureId = -1;
mNextRemoteTextureOwnerId = RemoteTextureOwnerId();
return dt.forget();
}
void CanvasTranslator::RemoveTexture(int64_t aTextureId) {
mTextureDatas.erase(aTextureId);
{
// Don't erase the texture if still in use
auto result = mTextureInfo.find(aTextureId);
if (result == mTextureInfo.end() || --result->second.mLocked > 0) {
return;
}
mTextureInfo.erase(result);
}
// It is possible that the texture from the content process has never been
// forwarded from the GPU process, so make sure its descriptor is removed.
@ -645,11 +798,112 @@ void CanvasTranslator::RemoveTexture(int64_t aTextureId) {
}
TextureData* CanvasTranslator::LookupTextureData(int64_t aTextureId) {
TextureMap::const_iterator result = mTextureDatas.find(aTextureId);
if (result == mTextureDatas.end()) {
auto result = mTextureInfo.find(aTextureId);
if (result == mTextureInfo.end()) {
return nullptr;
}
return result->second.get();
return result->second.mTextureData.get();
}
bool CanvasTranslator::LockTexture(int64_t aTextureId, OpenMode aMode,
RemoteTextureId aId) {
auto result = mTextureInfo.find(aTextureId);
if (result == mTextureInfo.end()) {
return false;
}
if (result->second.mDrawTarget &&
result->second.mDrawTarget->GetBackendType() == gfx::BackendType::WEBGL) {
gfx::DrawTargetWebgl* webgl =
static_cast<gfx::DrawTargetWebgl*>(result->second.mDrawTarget.get());
webgl->BeginFrame(webgl->GetRect());
} else if (TextureData* data = result->second.mTextureData.get()) {
if (!data->Lock(aMode)) {
return false;
}
}
return true;
}
bool CanvasTranslator::UnlockTexture(int64_t aTextureId, RemoteTextureId aId) {
auto result = mTextureInfo.find(aTextureId);
if (result == mTextureInfo.end()) {
return false;
}
RemoteTextureOwnerId ownerId = result->second.mRemoteTextureOwnerId;
if (result->second.mDrawTarget &&
result->second.mDrawTarget->GetBackendType() == gfx::BackendType::WEBGL) {
gfx::DrawTargetWebgl* webgl =
static_cast<gfx::DrawTargetWebgl*>(result->second.mDrawTarget.get());
webgl->EndFrame();
webgl->CopyToSwapChain(aId, ownerId, mOtherPid);
if (!result->second.mNotifiedRequiresRefresh && webgl->RequiresRefresh()) {
result->second.mNotifiedRequiresRefresh = true;
NotifyRequiresRefresh(aTextureId);
}
} else if (TextureData* data = result->second.mTextureData.get()) {
if (aId.IsValid()) {
PushRemoteTexture(data, aId, ownerId);
data->Unlock();
} else {
data->Unlock();
gfx::CanvasManagerParent::AddReplayTexture(this, aTextureId, data);
}
}
return true;
}
bool CanvasTranslator::PushRemoteTexture(TextureData* aData,
RemoteTextureId aId,
RemoteTextureOwnerId aOwnerId) {
if (!mRemoteTextureOwner) {
mRemoteTextureOwner = new RemoteTextureOwnerClient(mOtherPid);
}
if (!mRemoteTextureOwner->IsRegistered(aOwnerId)) {
mRemoteTextureOwner->RegisterTextureOwner(
aOwnerId,
/* aIsSyncMode */ gfx::gfxVars::WebglOopAsyncPresentForceSync());
}
TextureData::Info info;
aData->FillInfo(info);
UniquePtr<TextureData> dstData;
if (mTextureType == TextureType::Unknown) {
dstData = mRemoteTextureOwner->CreateOrRecycleBufferTextureData(
aOwnerId, info.size, info.format);
} else {
dstData.reset(
CreateTextureData(mTextureType, mBackendType, info.size, info.format));
}
bool success = false;
// Source data is already locked.
if (dstData && dstData->Lock(OpenMode::OPEN_WRITE)) {
if (RefPtr<gfx::DrawTarget> dstDT = dstData->BorrowDrawTarget()) {
if (RefPtr<gfx::DrawTarget> srcDT = aData->BorrowDrawTarget()) {
if (RefPtr<gfx::SourceSurface> snapshot = srcDT->Snapshot()) {
dstDT->CopySurface(snapshot, snapshot->GetRect(),
gfx::IntPoint(0, 0));
success = true;
}
}
}
dstData->Unlock();
}
if (success) {
mRemoteTextureOwner->PushTexture(aId, aOwnerId, std::move(dstData));
} else {
mRemoteTextureOwner->PushDummyTexture(aId, aOwnerId);
}
return success;
}
void CanvasTranslator::ClearTextureInfo() {
mTextureInfo.clear();
mDrawTargets.Clear();
mSharedContext = nullptr;
mBaseDT = nullptr;
if (mRemoteTextureOwner) {
mRemoteTextureOwner->UnregisterAllTextureOwners();
mRemoteTextureOwner = nullptr;
}
}
already_AddRefed<gfx::SourceSurface> CanvasTranslator::LookupExternalSurface(

Просмотреть файл

@ -17,6 +17,7 @@
#include "mozilla/layers/CanvasDrawEventRecorder.h"
#include "mozilla/layers/LayersSurfaces.h"
#include "mozilla/layers/PCanvasParent.h"
#include "mozilla/layers/RemoteTextureMap.h"
#include "mozilla/ipc/CrossProcessSemaphore.h"
#include "mozilla/Monitor.h"
#include "mozilla/UniquePtr.h"
@ -26,6 +27,11 @@ namespace mozilla {
using EventType = gfx::RecordedEvent::EventType;
class TaskQueue;
namespace gfx {
class DrawTargetWebgl;
class SharedContextWebgl;
} // namespace gfx
namespace layers {
class SharedSurfacesHolder;
@ -63,6 +69,7 @@ class CanvasTranslator final : public gfx::InlineTranslator,
* CanvasEventRingBuffer.
*
* @param aTextureType the TextureType the translator will create
* @param aBackendType the BackendType for texture data
* @param aHeaderHandle handle for the control header
* @param aBufferHandles handles for the initial buffers for translation
* @param aBufferSize size of buffers and the default size
@ -71,13 +78,11 @@ class CanvasTranslator final : public gfx::InlineTranslator,
* @param aUseIPDLThread if true, use the IPDL thread instead of the worker
* pool for translation requests
*/
ipc::IPCResult RecvInitTranslator(const TextureType& aTextureType,
Handle&& aReadHandle,
nsTArray<Handle>&& aBufferHandles,
uint64_t aBufferSize,
CrossProcessSemaphoreHandle&& aReaderSem,
CrossProcessSemaphoreHandle&& aWriterSem,
bool aUseIPDLThread);
ipc::IPCResult RecvInitTranslator(
TextureType aTextureType, gfx::BackendType aBackendType,
Handle&& aReadHandle, nsTArray<Handle>&& aBufferHandles,
uint64_t aBufferSize, CrossProcessSemaphoreHandle&& aReaderSem,
CrossProcessSemaphoreHandle&& aWriterSem, bool aUseIPDLThread);
/**
* Restart the translation from a Stopped state.
@ -134,8 +139,9 @@ class CanvasTranslator final : public gfx::InlineTranslator,
* Set the texture ID that will be used as a lookup for the texture created by
* the next CreateDrawTarget.
*/
void SetNextTextureId(int64_t aNextTextureId) {
void SetNextTextureId(int64_t aNextTextureId, RemoteTextureOwnerId aOwnerId) {
mNextTextureId = aNextTextureId;
mNextRemoteTextureOwnerId = aOwnerId;
}
/**
@ -175,6 +181,12 @@ class CanvasTranslator final : public gfx::InlineTranslator,
*/
void RemoveTexture(int64_t aTextureId);
bool LockTexture(int64_t aTextureId, OpenMode aMode, RemoteTextureId aId);
bool UnlockTexture(int64_t aTextureId, RemoteTextureId aId);
bool PushRemoteTexture(TextureData* aData, RemoteTextureId aId,
RemoteTextureOwnerId aOwnerId);
/**
* Overriden to remove any DataSourceSurfaces associated with the RefPtr.
*
@ -256,6 +268,8 @@ class CanvasTranslator final : public gfx::InlineTranslator,
UniquePtr<gfx::DataSourceSurface::ScopedMap> GetPreparedMap(
gfx::ReferencePtr aSurface);
void PrepareShmem(int64_t aTextureId);
void RecycleBuffer();
void NextBuffer();
@ -281,11 +295,14 @@ class CanvasTranslator final : public gfx::InlineTranslator,
void Deactivate();
void BlockCanvas();
TextureData* CreateTextureData(TextureType aTextureType,
gfx::BackendType aBackendType,
const gfx::IntSize& aSize,
gfx::SurfaceFormat aFormat);
void AddSurfaceDescriptor(int64_t aTextureId, TextureData* atextureData);
void ClearTextureInfo();
bool HandleExtensionEvent(int32_t aType);
@ -293,11 +310,18 @@ class CanvasTranslator final : public gfx::InlineTranslator,
bool CheckForFreshCanvasDevice(int aLineNumber);
void NotifyDeviceChanged();
bool EnsureSharedContextWebgl();
gfx::DrawTargetWebgl* GetDrawTargetWebgl(int64_t aTextureId) const;
void NotifyRequiresRefresh(int64_t aTextureId, bool aDispatch = true);
void CacheSnapshotShmem(int64_t aTextureId, bool aDispatch = true);
RefPtr<TaskQueue> mTranslationTaskQueue;
RefPtr<SharedSurfacesHolder> mSharedSurfacesHolder;
#if defined(XP_WIN)
RefPtr<ID3D11Device> mDevice;
#endif
RefPtr<gfx::SharedContextWebgl> mSharedContext;
RefPtr<RemoteTextureOwnerClient> mRemoteTextureOwner;
size_t mDefaultBufferSize = 0;
uint32_t mMaxSpinCount;
@ -329,13 +353,23 @@ class CanvasTranslator final : public gfx::InlineTranslator,
// Sometimes during device reset our reference DrawTarget can be null, so we
// hold the BackendType separately.
gfx::BackendType mBackendType = gfx::BackendType::NONE;
typedef std::unordered_map<int64_t, UniquePtr<TextureData>> TextureMap;
TextureMap mTextureDatas;
base::ProcessId mOtherPid = base::kInvalidProcessId;
struct TextureInfo {
UniquePtr<TextureData> mTextureData;
RefPtr<gfx::DrawTarget> mDrawTarget;
RemoteTextureOwnerId mRemoteTextureOwnerId;
bool mNotifiedRequiresRefresh = false;
// Ref-count of how active uses of the DT. Avoids deletion when locked.
int32_t mLocked = 1;
};
std::unordered_map<int64_t, TextureInfo> mTextureInfo;
int64_t mNextTextureId = -1;
RemoteTextureOwnerId mNextRemoteTextureOwnerId;
nsRefPtrHashtable<nsPtrHashKey<void>, gfx::DataSourceSurface> mDataSurfaces;
gfx::ReferencePtr mMappedSurface;
UniquePtr<gfx::DataSourceSurface::ScopedMap> mPreparedMap;
Atomic<bool> mDeactivated{false};
Atomic<bool> mBlocked{false};
bool mIsInTransaction = false;
bool mDeviceResetInProgress = false;
};

Просмотреть файл

@ -517,7 +517,7 @@ PTextureChild* CompositorBridgeChild::CreateTexture(
}
already_AddRefed<CanvasChild> CompositorBridgeChild::GetCanvasChild() {
MOZ_ASSERT(gfx::gfxVars::RemoteCanvasEnabled());
MOZ_ASSERT(gfxPlatform::UseRemoteCanvas());
if (auto* cm = gfx::CanvasManagerChild::Get()) {
return cm->GetCanvasChild().forget();
}

Просмотреть файл

@ -11,6 +11,7 @@ include "mozilla/layers/CanvasTranslator.h";
[MoveOnly] using mozilla::CrossProcessSemaphoreHandle from "mozilla/ipc/CrossProcessSemaphore.h";
using mozilla::layers::TextureType from "mozilla/layers/LayersTypes.h";
[MoveOnly] using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasic.h";
using mozilla::gfx::BackendType from "mozilla/gfx/Types.h";
namespace mozilla {
namespace layers {
@ -33,8 +34,9 @@ parent:
* aUseIPDLThread if true, use the IPDL thread instead of the worker pool for
* translation requests
*/
async InitTranslator(TextureType aTextureType, Handle aHeaderHandle,
Handle[] aBufferHandles, uint64_t aBufferSize,
async InitTranslator(TextureType aTextureType, BackendType aBackendType,
Handle aHeaderHandle, Handle[] aBufferHandles,
uint64_t aBufferSize,
CrossProcessSemaphoreHandle aReaderSem,
CrossProcessSemaphoreHandle aWriterSem,
bool aUseIPDLThread);
@ -67,6 +69,22 @@ child:
* Deactivate remote canvas, which will cause fall back to software.
*/
async Deactivate();
/**
* Block further accelerated canvases from being created, but allow existing
* canvases to continue processing.
*/
async BlockCanvas();
/**
* Notify that a remote accelerated canvas requires a fallback refresh.
*/
async NotifyRequiresRefresh(int64_t aTextureId);
/**
* Cache the shmem of the framebuffer for snapshotting.
*/
async SnapshotShmem(int64_t aTextureId, Handle aShmemHandle, uint32_t aShmemSize) returns (bool aSuccess);
};
} // layers

Просмотреть файл

@ -143,6 +143,7 @@ void WebRenderImageHost::PushPendingRemoteTexture(
// Clear when RemoteTextureOwner is different.
mPendingRemoteTextureWrappers.clear();
mWaitingReadyCallback = false;
mWaitForRemoteTextureOwner = true;
}
}
@ -222,7 +223,8 @@ void WebRenderImageHost::UseRemoteTexture() {
std::function<void(const RemoteTextureInfo&)> function;
RemoteTextureMap::Get()->GetRemoteTextureForDisplayList(
wrapper, std::move(function));
wrapper, std::move(function), mWaitForRemoteTextureOwner);
mWaitForRemoteTextureOwner = false;
}
if (!texture ||

Просмотреть файл

@ -88,6 +88,7 @@ class WebRenderImageHost : public CompositableHost, public ImageComposite {
std::deque<CompositableTextureHostRef> mPendingRemoteTextureWrappers;
bool mWaitingReadyCallback = false;
bool mWaitForRemoteTextureOwner = true;
Maybe<RemoteTextureOwnerId> mRemoteTextureOwnerIdOfPushCallback;
base::ProcessId mForPidOfPushCallback;

Просмотреть файл

@ -1189,7 +1189,8 @@ bool gfxPlatform::IsHeadless() {
/* static */
bool gfxPlatform::UseRemoteCanvas() {
return XRE_IsContentProcess() && gfx::gfxVars::RemoteCanvasEnabled();
return XRE_IsContentProcess() && (gfx::gfxVars::RemoteCanvasEnabled() ||
gfx::gfxVars::UseAcceleratedCanvas2D());
}
/* static */
@ -3871,13 +3872,18 @@ void gfxPlatform::DisableGPUProcess() {
}
/* static */ void gfxPlatform::DisableRemoteCanvas() {
if (!gfxVars::RemoteCanvasEnabled()) {
return;
if (gfxVars::RemoteCanvasEnabled()) {
gfxConfig::ForceDisable(Feature::REMOTE_CANVAS, FeatureStatus::Failed,
"Disabled by runtime error",
"FEATURE_REMOTE_CANVAS_RUNTIME_ERROR"_ns);
gfxVars::SetRemoteCanvasEnabled(false);
}
if (gfxVars::UseAcceleratedCanvas2D()) {
gfxConfig::ForceDisable(Feature::ACCELERATED_CANVAS2D,
FeatureStatus::Failed, "Disabled by runtime error",
"FEATURE_ACCELERATED_CANVAS2D_RUNTIME_ERROR"_ns);
gfxVars::SetUseAcceleratedCanvas2D(false);
}
gfxConfig::ForceDisable(Feature::REMOTE_CANVAS, FeatureStatus::Failed,
"Disabled by runtime error",
"FEATURE_REMOTE_CANVAS_RUNTIME_ERROR"_ns);
gfxVars::SetRemoteCanvasEnabled(false);
}
void gfxPlatform::ImportCachedContentDeviceData() {

Просмотреть файл

@ -104,7 +104,7 @@ fuzzy(0-1,0-43) == 1201272-1.html 1201272-1-ref.html
== 1303534-1.html 1303534-1-ref.html
fuzzy-if(cocoaWidget,0-1,0-1410) == 1304353-text-global-alpha-1.html 1304353-text-global-alpha-1-ref.html
fuzzy-if(cocoaWidget,0-1,0-1302) fuzzy-if(winWidget,0-1,0-578) == 1304353-text-global-alpha-2.html 1304353-text-global-alpha-2-ref.html
fuzzy(0-1,0-1302) == 1304353-text-global-alpha-2.html 1304353-text-global-alpha-2-ref.html
fuzzy-if(winWidget,0-94,0-1575) fuzzy-if(cocoaWidget,0-1,0-34) == 1304353-text-global-composite-op-1.html 1304353-text-global-composite-op-1-ref.html
== text-indent-1a.html text-indent-1-ref.html

Просмотреть файл

@ -36,8 +36,8 @@ fails-if(useDrawSnapshot) == background-scale-with-viewbox-1.html background-sca
== canvas-drawImage-scale-1b.html lime100x100-ref.html
== canvas-drawImage-scale-1c.html lime100x100-ref.html
fuzzy(0-1,0-2) fuzzy-if(!remoteCanvas,0-1,0-529) fuzzy-if(remoteCanvas,0-97,0-745) fuzzy-if(Android&&device,0-64,0-1212) == canvas-drawImage-scale-2a.html canvas-drawImage-scale-2-ref.html
fuzzy(0-1,0-2) fuzzy-if(!remoteCanvas,0-1,0-529) fuzzy-if(remoteCanvas,0-97,0-745) fuzzy-if(Android&&device,0-64,0-1212) == canvas-drawImage-scale-2b.html canvas-drawImage-scale-2-ref.html
fuzzy(0-192,0-2112) == canvas-drawImage-scale-2a.html canvas-drawImage-scale-2-ref.html
fuzzy(0-192,0-2112) == canvas-drawImage-scale-2b.html canvas-drawImage-scale-2-ref.html
fuzzy-if(winWidget,0-1,0-10000) fuzzy-if(azureSkia,0-1,0-10000) fuzzy-if(Android,0-1,0-10000) == canvas-drawImage-alpha-1.html canvas-drawImage-alpha-1-ref.html
#Same as scale-2a but with globalAlpha:

Просмотреть файл

@ -2,6 +2,6 @@
# e.g. filter: blur(3px) grayscale(0.5) invert(0.2);
# Some platforms render this complex filter chain a little differently, and that's ok.
fuzzy(4-6,12000-19950) fuzzy-if(swgl,5-10,13600-20260) fuzzy-if(Android&&device&&!swgl,6-6,19986-19986) == long-chain.html long-chain-ref.html # Win10: Bug 1258241
fuzzy(4-10,12000-20260) == long-chain.html long-chain-ref.html # Win10: Bug 1258241
== moz-element.html moz-element-ref.html
fuzzy-if(!useDrawSnapshot,13-15,7670-7982) fuzzy-if(!useDrawSnapshot&&swgl,11-12,14052-14056) fuzzy-if(Android&&device&&!swgl,13-13,13505-13505) == same-filter.html same-filter-ref.html
fuzzy(0-15,0-14056) == same-filter.html same-filter-ref.html