forked from mirrors/gecko-dev
If we are re-forwarding a texture that has not been updated then it might still be read locked. We rely on the read lock for us to know when the Compositor or Renderer has finished with the texture. So this change copies it to a new texture, which we can safely read lock. If the texture is not read locked then we ensure that it is set as updated, which means we will read lock it as we forward it. Differential Revision: https://phabricator.services.mozilla.com/D119546
216 lines
5.6 KiB
C++
216 lines
5.6 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"
|
|
|
|
#ifdef MOZ_WIDGET_ANDROID
|
|
# include "mozilla/layers/AndroidHardwareBuffer.h"
|
|
#endif
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
if (desc.type() !=
|
|
SurfaceDescriptor::TSurfaceDescriptorAndroidHardwareBuffer) {
|
|
mFrontBufferFromDesc = SharedSurfaceTextureData::CreateTextureClient(
|
|
desc, format, mData.mSize, flags, textureForwarder);
|
|
} else {
|
|
#ifdef MOZ_WIDGET_ANDROID
|
|
const SurfaceDescriptorAndroidHardwareBuffer& bufferDesc =
|
|
desc.get_SurfaceDescriptorAndroidHardwareBuffer();
|
|
RefPtr<AndroidHardwareBuffer> buffer =
|
|
AndroidHardwareBufferManager::Get()->GetBuffer(bufferDesc.bufferId());
|
|
if (!buffer) {
|
|
return nullptr;
|
|
}
|
|
// TextureClient is created only when AndroidHardwareBuffer does not own it.
|
|
mFrontBufferFromDesc = buffer->GetTextureClientOfSharedSurfaceTextureData(
|
|
desc, format, mData.mSize, flags, textureForwarder);
|
|
#else
|
|
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
|
|
#endif
|
|
}
|
|
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 webgl = context->AsWebgl();
|
|
|
|
const auto& forwarder = GetForwarder();
|
|
|
|
// -
|
|
|
|
auto flags = TextureFlags::IMMUTABLE;
|
|
if (!YIsDown()) {
|
|
flags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
|
|
}
|
|
if (IsOpaque()) {
|
|
flags |= TextureFlags::IS_OPAQUE;
|
|
}
|
|
|
|
// -
|
|
|
|
const auto fnGetExistingTc = [&]() -> RefPtr<TextureClient> {
|
|
if (provider) {
|
|
if (!provider->SetKnowsCompositor(forwarder)) {
|
|
gfxCriticalNote << "BufferProvider::SetForwarder failed";
|
|
return nullptr;
|
|
}
|
|
|
|
return provider->GetTextureClient();
|
|
}
|
|
|
|
if (!webgl) return nullptr;
|
|
|
|
const auto desc = webgl->GetFrontBuffer(nullptr);
|
|
if (!desc) return nullptr;
|
|
return GetFrontBufferFromDesc(*desc, flags);
|
|
};
|
|
|
|
// -
|
|
|
|
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;
|
|
const auto borrowed = BorrowSnapshot(requireAlphaPremult);
|
|
if (!borrowed) return nullptr;
|
|
|
|
dt->CopySurface(borrowed->mSurf, {{0, 0}, size}, {0, 0});
|
|
}
|
|
|
|
return tc;
|
|
};
|
|
|
|
// -
|
|
|
|
{
|
|
FirePreTransactionCallback();
|
|
|
|
// First, let's see if we can get a no-copy TextureClient from the canvas.
|
|
auto tc = fnGetExistingTc();
|
|
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
|