forked from mirrors/gecko-dev
UnregisterTextureOwner, if called before any use of UseRemoteTexture, can cause UseRemoteTexture to wait for the texture owner to be created, since the texture owner does not exist, and there is no evidence it was previously unregistered. This patch attempts to address the issue by delaying the actual UnregisterTextureOwner until all such UseRemoteTexture instances are processed. This is accomplished by noting that UseRemoteTexture ops come in via transactions from a CompositableForwarder and so all are associated with a forwarder transaction with a FwdTransactionId. RecordedTextureData on destruction reports the last FwdTransactionId associated with its final UseRemoteTexture before it attempts to call UnregisterTextureOwner. If RemoteTextureMap has not been notified of a given FwdTransactionId yet, then the UnregisterTextureOwner call will be deferred until it has seen this FwdTransactionId. This adds a RemoteTextureTxnScheduler to track the issuing of dependencies and waiting for FwdTransactionIds. This patch also cleans up the issuing of FwdTransactionIds themselves to be associated with a given top-level protocol so that all sub-protocols have transaction numbers that can be safely compared amongst each other. This makes dependency expiration more robust since any advancement of the transaction number from any source can help retire expired dependencies. Differential Revision: https://phabricator.services.mozilla.com/D197895
235 lines
6.2 KiB
C++
235 lines
6.2 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "ShareableCanvasRenderer.h"
|
|
|
|
#include "mozilla/dom/WebGLTypes.h"
|
|
#include "mozilla/gfx/2D.h"
|
|
#include "mozilla/layers/TextureClientSharedSurface.h"
|
|
#include "mozilla/layers/CompositableForwarder.h"
|
|
#include "mozilla/layers/TextureForwarder.h"
|
|
|
|
#include "ClientWebGLContext.h"
|
|
#include "gfxUtils.h"
|
|
#include "GLScreenBuffer.h"
|
|
#include "nsICanvasRenderingContextInternal.h"
|
|
#include "SharedSurfaceGL.h"
|
|
|
|
using namespace mozilla::gfx;
|
|
|
|
namespace mozilla {
|
|
namespace layers {
|
|
|
|
ShareableCanvasRenderer::ShareableCanvasRenderer() {
|
|
MOZ_COUNT_CTOR(ShareableCanvasRenderer);
|
|
}
|
|
|
|
ShareableCanvasRenderer::~ShareableCanvasRenderer() {
|
|
MOZ_COUNT_DTOR(ShareableCanvasRenderer);
|
|
|
|
mFrontBufferFromDesc = nullptr;
|
|
DisconnectClient();
|
|
}
|
|
|
|
void ShareableCanvasRenderer::Initialize(const CanvasRendererData& aData) {
|
|
CanvasRenderer::Initialize(aData);
|
|
mCanvasClient = nullptr;
|
|
}
|
|
|
|
void ShareableCanvasRenderer::ClearCachedResources() {
|
|
CanvasRenderer::ClearCachedResources();
|
|
|
|
if (mCanvasClient) {
|
|
mCanvasClient->Clear();
|
|
}
|
|
}
|
|
|
|
void ShareableCanvasRenderer::DisconnectClient() {
|
|
if (mCanvasClient) {
|
|
mCanvasClient->OnDetach();
|
|
mCanvasClient = nullptr;
|
|
}
|
|
}
|
|
|
|
RefPtr<layers::TextureClient> ShareableCanvasRenderer::GetFrontBufferFromDesc(
|
|
const layers::SurfaceDescriptor& desc, TextureFlags flags) {
|
|
if (mFrontBufferFromDesc && mFrontBufferDesc == desc)
|
|
return mFrontBufferFromDesc;
|
|
mFrontBufferFromDesc = nullptr;
|
|
|
|
// Test the validity of aAllocator
|
|
const auto& compositableForwarder = GetForwarder();
|
|
if (!compositableForwarder) {
|
|
return nullptr;
|
|
}
|
|
const auto& textureForwarder = compositableForwarder->GetTextureForwarder();
|
|
|
|
auto format = gfx::SurfaceFormat::R8G8B8X8;
|
|
if (!mData.mIsOpaque) {
|
|
format = gfx::SurfaceFormat::R8G8B8A8;
|
|
|
|
if (!mData.mIsAlphaPremult) {
|
|
flags |= TextureFlags::NON_PREMULTIPLIED;
|
|
}
|
|
}
|
|
|
|
mFrontBufferFromDesc = SharedSurfaceTextureData::CreateTextureClient(
|
|
desc, format, mData.mSize, flags, textureForwarder);
|
|
mFrontBufferDesc = desc;
|
|
return mFrontBufferFromDesc;
|
|
}
|
|
|
|
void ShareableCanvasRenderer::UpdateCompositableClient() {
|
|
if (!CreateCompositable()) {
|
|
return;
|
|
}
|
|
|
|
if (!IsDirty()) {
|
|
return;
|
|
}
|
|
ResetDirty();
|
|
|
|
const auto context = mData.GetContext();
|
|
if (!context) return;
|
|
const auto& provider = context->GetBufferProvider();
|
|
const auto& forwarder = GetForwarder();
|
|
|
|
// -
|
|
|
|
auto flags = TextureFlags::IMMUTABLE;
|
|
if (!YIsDown()) {
|
|
flags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
|
|
}
|
|
if (IsOpaque()) {
|
|
flags |= TextureFlags::IS_OPAQUE;
|
|
}
|
|
|
|
// With remote texture push callback, a new pushed remote texture is notifiled
|
|
// from RemoteTextureMap to WebRenderImageHost.
|
|
if (mData.mRemoteTextureOwnerIdOfPushCallback) {
|
|
if (!HasPipeline()) {
|
|
GetForwarder()->EnableRemoteTexturePushCallback(
|
|
mCanvasClient, *mData.mRemoteTextureOwnerIdOfPushCallback,
|
|
mData.mSize, flags);
|
|
EnsurePipeline();
|
|
}
|
|
// Post front buffer
|
|
context->GetFrontBuffer(nullptr);
|
|
return;
|
|
}
|
|
|
|
// -
|
|
|
|
const auto fnGetExistingTc =
|
|
[&](const Maybe<SurfaceDescriptor>& aDesc,
|
|
bool& aOutLostFrontTexture) -> RefPtr<TextureClient> {
|
|
if (aDesc) {
|
|
return GetFrontBufferFromDesc(*aDesc, flags);
|
|
}
|
|
if (provider) {
|
|
if (!provider->SetKnowsCompositor(forwarder, aOutLostFrontTexture)) {
|
|
gfxCriticalNote << "BufferProvider::SetForwarder failed";
|
|
return nullptr;
|
|
}
|
|
if (aOutLostFrontTexture) {
|
|
return nullptr;
|
|
}
|
|
|
|
return provider->GetTextureClient();
|
|
}
|
|
return nullptr;
|
|
};
|
|
|
|
// -
|
|
|
|
const auto fnMakeTcFromSnapshot = [&]() -> RefPtr<TextureClient> {
|
|
const auto& size = mData.mSize;
|
|
|
|
auto contentType = gfxContentType::COLOR;
|
|
if (!mData.mIsOpaque) {
|
|
contentType = gfxContentType::COLOR_ALPHA;
|
|
}
|
|
const auto surfaceFormat =
|
|
gfxPlatform::GetPlatform()->Optimal2DFormatForContent(contentType);
|
|
|
|
const auto tc =
|
|
mCanvasClient->CreateTextureClientForCanvas(surfaceFormat, size, flags);
|
|
if (!tc) {
|
|
return nullptr;
|
|
}
|
|
|
|
{
|
|
TextureClientAutoLock tcLock(tc, OpenMode::OPEN_WRITE_ONLY);
|
|
if (!tcLock.Succeeded()) {
|
|
return nullptr;
|
|
}
|
|
|
|
const RefPtr<DrawTarget> dt = tc->BorrowDrawTarget();
|
|
|
|
const bool requireAlphaPremult = false;
|
|
auto borrowed = BorrowSnapshot(requireAlphaPremult);
|
|
if (!borrowed) {
|
|
return nullptr;
|
|
}
|
|
dt->CopySurface(borrowed->mSurf, borrowed->mSurf->GetRect(), {0, 0});
|
|
}
|
|
|
|
return tc;
|
|
};
|
|
|
|
// -
|
|
|
|
{
|
|
FirePreTransactionCallback();
|
|
|
|
const auto desc = context->GetFrontBuffer(nullptr);
|
|
if (desc &&
|
|
desc->type() == SurfaceDescriptor::TSurfaceDescriptorRemoteTexture) {
|
|
const auto& forwarder = GetForwarder();
|
|
const auto& textureDesc = desc->get_SurfaceDescriptorRemoteTexture();
|
|
if (!mData.mIsAlphaPremult) {
|
|
flags |= TextureFlags::NON_PREMULTIPLIED;
|
|
}
|
|
EnsurePipeline();
|
|
forwarder->UseRemoteTexture(mCanvasClient, textureDesc.textureId(),
|
|
textureDesc.ownerId(), mData.mSize, flags);
|
|
if (provider) {
|
|
provider->UseCompositableForwarder(forwarder);
|
|
}
|
|
FireDidTransactionCallback();
|
|
return;
|
|
}
|
|
|
|
EnsurePipeline();
|
|
|
|
// Let's see if we can get a no-copy TextureClient from the canvas.
|
|
bool lostFrontTexture = false;
|
|
auto tc = fnGetExistingTc(desc, lostFrontTexture);
|
|
if (lostFrontTexture) {
|
|
// Device reset could cause this.
|
|
return;
|
|
}
|
|
if (!tc) {
|
|
// Otherwise, snapshot the surface and copy into a TexClient.
|
|
tc = fnMakeTcFromSnapshot();
|
|
}
|
|
if (tc != mFrontBufferFromDesc) {
|
|
mFrontBufferFromDesc = nullptr;
|
|
}
|
|
|
|
if (!tc) {
|
|
NS_WARNING("Couldn't make TextureClient for CanvasRenderer.");
|
|
return;
|
|
}
|
|
|
|
mCanvasClient->UseTexture(tc);
|
|
|
|
FireDidTransactionCallback();
|
|
}
|
|
}
|
|
|
|
} // namespace layers
|
|
} // namespace mozilla
|