Bug 1673342 - Add Support of software WebRender with CompositorOGL on Android and Linux r=mattwoodrow

Differential Revision: https://phabricator.services.mozilla.com/D106234
This commit is contained in:
sotaro
2021-03-01 13:45:38 +00:00
parent 73efd7055e
commit e6e6c2e2d2
13 changed files with 462 additions and 15 deletions

View File

@@ -188,6 +188,7 @@ enum class WebRenderCompositor : int8_t {
CORE_ANIMATION,
SOFTWARE,
D3D11,
OPENGL,
LAST
};

View File

@@ -164,6 +164,16 @@ class KnowsCompositor {
layers::WebRenderCompositor::D3D11;
}
bool UsingSoftwareWebRenderOpenGL() const {
auto lock = mData.Lock();
return lock.ref().mTextureFactoryIdentifier.mParentBackend ==
layers::LayersBackend::LAYERS_WR &&
lock.ref().mTextureFactoryIdentifier.mWebRenderBackend ==
WebRenderBackend::SOFTWARE &&
lock.ref().mTextureFactoryIdentifier.mWebRenderCompositor ==
layers::WebRenderCompositor::OPENGL;
}
TextureFactoryIdentifier GetTextureFactoryIdentifier() const {
auto lock = mData.Lock();
return lock.ref().mTextureFactoryIdentifier;

View File

@@ -358,23 +358,40 @@ void CompositorOGL::CleanupResources() {
mBlitTextureImageHelper = nullptr;
// On the main thread the Widget will be destroyed soon and calling
// MakeCurrent after that could cause a crash (at least with GLX, see bug
// 1059793), unless context is marked as destroyed. There may be some textures
// still alive that will try to call MakeCurrent on the context so let's make
// sure it is marked destroyed now.
mGLContext->MarkDestroyed();
if (mOwnsGLContext) {
// On the main thread the Widget will be destroyed soon and calling
// MakeCurrent after that could cause a crash (at least with GLX, see bug
// 1059793), unless context is marked as destroyed. There may be some
// textures still alive that will try to call MakeCurrent on the context so
// let's make sure it is marked destroyed now.
mGLContext->MarkDestroyed();
}
mGLContext = nullptr;
}
bool CompositorOGL::Initialize(GLContext* aGLContext,
nsCString* const out_failureReason) {
MOZ_ASSERT(!mDestroyed);
MOZ_ASSERT(!mGLContext);
mGLContext = aGLContext;
mOwnsGLContext = false;
return Initialize(out_failureReason);
}
bool CompositorOGL::Initialize(nsCString* const out_failureReason) {
ScopedGfxFeatureReporter reporter("GL Layers");
// Do not allow double initialization
MOZ_ASSERT(mGLContext == nullptr, "Don't reinitialize CompositorOGL");
MOZ_ASSERT(mGLContext == nullptr || !mOwnsGLContext,
"Don't reinitialize CompositorOGL");
mGLContext = CreateContext();
if (!mGLContext) {
MOZ_ASSERT(mOwnsGLContext);
mGLContext = CreateContext();
}
#ifdef MOZ_WIDGET_ANDROID
if (!mGLContext) {

View File

@@ -130,6 +130,8 @@ class CompositorOGL final : public Compositor {
already_AddRefed<DataTextureSource> CreateDataTextureSourceAround(
gfx::DataSourceSurface* aSurface) override;
bool Initialize(GLContext* aGLContext, nsCString* const out_failureReason);
bool Initialize(nsCString* const out_failureReason) override;
void Destroy() override;
@@ -285,6 +287,7 @@ class CompositorOGL final : public Compositor {
/** Widget associated with this compositor */
LayoutDeviceIntSize mWidgetSize;
RefPtr<GLContext> mGLContext;
bool mOwnsGLContext = true;
RefPtr<SurfacePoolHandle> mSurfacePoolHandle;
UniquePtr<GLBlitTextureImageHelper> mBlitTextureImageHelper;
gfx::Matrix4x4 mProjMatrix;

View File

@@ -168,6 +168,8 @@ CompositorBridgeChild* WebRenderLayerManager::GetCompositorBridgeChild() {
void WebRenderLayerManager::GetBackendName(nsAString& name) {
if (WrBridge()->UsingSoftwareWebRenderD3D11()) {
name.AssignLiteral("WebRender (Software D3D11)");
} else if (WrBridge()->UsingSoftwareWebRenderOpenGL()) {
name.AssignLiteral("WebRender (Software OpenGL)");
} else if (WrBridge()->UsingSoftwareWebRender()) {
name.AssignLiteral("WebRender (Software)");
} else {

View File

@@ -50,6 +50,18 @@ class RenderAndroidSurfaceTextureHost final : public RenderTextureHostSWGL {
return gfx::YUVColorSpace::UNKNOWN;
}
RenderAndroidSurfaceTextureHost* AsRenderAndroidSurfaceTextureHost()
override {
return this;
}
mozilla::java::GeckoSurfaceTexture::GlobalRef mSurfTex;
const gfx::IntSize mSize;
const gfx::SurfaceFormat mFormat;
// mContinuousUpdate was used for rendering video in the past.
// It is not used on current gecko.
const bool mContinuousUpdate;
private:
virtual ~RenderAndroidSurfaceTextureHost();
bool EnsureAttachedToGLContext();
@@ -63,12 +75,6 @@ class RenderAndroidSurfaceTextureHost final : public RenderTextureHostSWGL {
STATUS_PREPARED
};
const mozilla::java::GeckoSurfaceTexture::GlobalRef mSurfTex;
const gfx::IntSize mSize;
const gfx::SurfaceFormat mFormat;
// mContinuousUpdate was used for rendering video in the past.
// It is not used on current gecko.
const bool mContinuousUpdate;
// XXX const bool mIgnoreTransform;
PrepareStatus mPrepareStatus;
bool mAttachedToGLContext;

View File

@@ -32,6 +32,7 @@ class CompositorWidget;
namespace wr {
class RenderCompositorLayersSWGL;
class RenderCompositorD3D11SWGL;
class RenderCompositor {
@@ -93,6 +94,10 @@ class RenderCompositor {
return nullptr;
}
virtual RenderCompositorLayersSWGL* AsRenderCompositorLayersSWGL() {
return nullptr;
}
// True if AttachExternalImage supports being used with an external
// image that maps to a RenderBufferTextureHost
virtual bool SupportsExternalBufferTextures() const { return false; }

View File

@@ -19,6 +19,8 @@
#if defined(XP_WIN)
# include "mozilla/webrender/RenderCompositorD3D11SWGL.h"
#else
# include "mozilla/webrender/RenderCompositorOGLSWGL.h"
#endif
namespace mozilla {
@@ -31,7 +33,7 @@ UniquePtr<RenderCompositor> RenderCompositorLayersSWGL::Create(
#ifdef XP_WIN
return RenderCompositorD3D11SWGL::Create(std::move(aWidget), aError);
#else
return nullptr;
return RenderCompositorOGLSWGL::Create(std::move(aWidget), aError);
#endif
}
@@ -237,6 +239,8 @@ void RenderCompositorLayersSWGL::AttachExternalImage(
#if defined(XP_WIN)
MOZ_RELEASE_ASSERT(image->AsRenderDXGITextureHost() ||
image->AsRenderDXGIYCbCrTextureHost());
#elif defined(ANDROID)
MOZ_RELEASE_ASSERT(image->AsRenderAndroidSurfaceTextureHost());
#endif
auto surfaceCursor = mSurfaces.find(aId);

View File

@@ -0,0 +1,305 @@
/* -*- 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 "RenderCompositorOGLSWGL.h"
#include "GLContext.h"
#include "GLContextEGL.h"
#include "mozilla/layers/BuildConstants.h"
#include "mozilla/layers/CompositorOGL.h"
#include "mozilla/layers/Effects.h"
#include "mozilla/layers/TextureHostOGL.h"
#include "mozilla/widget/CompositorWidget.h"
#ifdef MOZ_WIDGET_ANDROID
# include "mozilla/java/GeckoSurfaceTextureWrappers.h"
# include "mozilla/widget/AndroidCompositorWidget.h"
# include <android/native_window.h>
# include <android/native_window_jni.h>
#endif
#ifdef MOZ_WIDGET_GTK
# include "mozilla/widget/GtkCompositorWidget.h"
# include <gdk/gdk.h>
# include <gdk/gdkx.h>
#endif
namespace mozilla {
using namespace layers;
namespace wr {
UniquePtr<RenderCompositor> RenderCompositorOGLSWGL::Create(
RefPtr<widget::CompositorWidget>&& aWidget, nsACString& aError) {
RefPtr<Compositor> compositor;
#ifdef MOZ_WIDGET_ANDROID
if (StaticPrefs::gfx_webrender_software_opengl_AtStartup()) {
RefPtr<gl::GLContext> context = RenderThread::Get()->SharedGL();
if (!context) {
gfxCriticalNote << "SharedGL does not exist for SWGL";
return nullptr;
}
nsCString log;
RefPtr<CompositorOGL> compositorOGL;
compositorOGL = new CompositorOGL(nullptr, aWidget, /* aSurfaceWidth */ -1,
/* aSurfaceHeight */ -1,
/* aUseExternalSurfaceSize */ true);
if (!compositorOGL->Initialize(context, &log)) {
gfxCriticalNote << "Failed to initialize CompositorOGL for SWGL: "
<< log.get();
return nullptr;
}
compositor = compositorOGL;
}
#elif defined(MOZ_WIDGET_GTK)
if (StaticPrefs::gfx_webrender_software_opengl_AtStartup()) {
nsCString log;
RefPtr<CompositorOGL> compositorOGL;
compositorOGL = new CompositorOGL(nullptr, aWidget);
if (!compositorOGL->Initialize(&log)) {
gfxCriticalNote << "Failed to initialize CompositorOGL for SWGL: "
<< log.get();
return nullptr;
}
compositor = compositorOGL;
}
#endif
if (!compositor) {
return nullptr;
}
void* ctx = wr_swgl_create_context();
if (!ctx) {
gfxCriticalNote << "Failed SWGL context creation for WebRender";
return nullptr;
}
return MakeUnique<RenderCompositorOGLSWGL>(compositor, std::move(aWidget),
ctx);
}
RenderCompositorOGLSWGL::RenderCompositorOGLSWGL(
Compositor* aCompositor, RefPtr<widget::CompositorWidget>&& aWidget,
void* aContext)
: RenderCompositorLayersSWGL(aCompositor, std::move(aWidget), aContext) {}
RenderCompositorOGLSWGL::~RenderCompositorOGLSWGL() {
#ifdef OZ_WIDGET_ANDROID
java::GeckoSurfaceTexture::DestroyUnused((int64_t)GetGLContext());
DestroyEGLSurface();
#endif
}
gl::GLContext* RenderCompositorOGLSWGL::GetGLContext() {
return mCompositor->AsCompositorOGL()->gl();
}
bool RenderCompositorOGLSWGL::MakeCurrent() {
GetGLContext()->MakeCurrent();
#ifdef MOZ_WIDGET_ANDROID
if (GetGLContext()->GetContextType() == gl::GLContextType::EGL) {
gl::GLContextEGL::Cast(GetGLContext())->SetEGLSurfaceOverride(mEGLSurface);
}
#endif
RenderCompositorLayersSWGL::MakeCurrent();
return true;
}
EGLSurface RenderCompositorOGLSWGL::CreateEGLSurface() {
MOZ_ASSERT(GetGLContext()->GetContextType() == gl::GLContextType::EGL);
EGLSurface surface = EGL_NO_SURFACE;
surface = gl::GLContextEGL::CreateEGLSurfaceForCompositorWidget(
mWidget, gl::GLContextEGL::Cast(GetGLContext())->mConfig);
if (surface == EGL_NO_SURFACE) {
gfxCriticalNote << "Failed to create EGLSurface";
}
return surface;
}
void RenderCompositorOGLSWGL::DestroyEGLSurface() {
MOZ_ASSERT(GetGLContext()->GetContextType() == gl::GLContextType::EGL);
const auto& gle = gl::GLContextEGL::Cast(GetGLContext());
const auto& egl = gle->mEgl;
// Release EGLSurface of back buffer before calling ResizeBuffers().
if (mEGLSurface) {
gle->SetEGLSurfaceOverride(EGL_NO_SURFACE);
egl->fDestroySurface(mEGLSurface);
mEGLSurface = EGL_NO_SURFACE;
}
}
bool RenderCompositorOGLSWGL::BeginFrame() {
MOZ_ASSERT(!mInFrame);
RenderCompositorLayersSWGL::BeginFrame();
#ifdef MOZ_WIDGET_ANDROID
java::GeckoSurfaceTexture::DestroyUnused((int64_t)GetGLContext());
GetGLContext()
->MakeCurrent(); // DestroyUnused can change the current context!
#endif
return true;
}
void RenderCompositorOGLSWGL::HandleExternalImage(
RenderTextureHost* aExternalImage, FrameSurface& aFrameSurface) {
MOZ_ASSERT(aExternalImage);
#ifdef MOZ_WIDGET_ANDROID
GLenum target =
LOCAL_GL_TEXTURE_EXTERNAL; // This is required by SurfaceTexture
GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
auto* host = aExternalImage->AsRenderAndroidSurfaceTextureHost();
// We need to hold the texture source separately from the effect,
// since the effect doesn't hold a strong reference.
RefPtr<SurfaceTextureSource> layer = new SurfaceTextureSource(
(TextureSourceProvider*)mCompositor, host->mSurfTex, host->mFormat,
target, wrapMode, host->mSize, /* aIgnoreTransform */ true);
RefPtr<TexturedEffect> texturedEffect =
CreateTexturedEffect(host->mFormat, layer, aFrameSurface.mFilter,
/* isAlphaPremultiplied */ true);
gfx::Rect drawRect(0, 0, host->mSize.width, host->mSize.height);
EffectChain effect;
effect.mPrimaryEffect = texturedEffect;
mCompositor->DrawQuad(drawRect, aFrameSurface.mClipRect, effect, 1.0,
aFrameSurface.mTransform, drawRect);
#endif
}
void RenderCompositorOGLSWGL::Pause() {
#ifdef MOZ_WIDGET_ANDROID
DestroyEGLSurface();
#elif defined(MOZ_WIDGET_GTK)
mCompositor->Pause();
#endif
}
bool RenderCompositorOGLSWGL::Resume() {
#ifdef MOZ_WIDGET_ANDROID
// Destroy EGLSurface if it exists.
DestroyEGLSurface();
// Query the new surface size as this may have changed. We cannot use
// mWidget->GetClientSize() due to a race condition between
// nsWindow::Resize() being called and the frame being rendered after the
// surface is resized.
EGLNativeWindowType window = mWidget->AsAndroid()->GetEGLNativeWindow();
JNIEnv* const env = jni::GetEnvForThread();
ANativeWindow* const nativeWindow =
ANativeWindow_fromSurface(env, reinterpret_cast<jobject>(window));
const int32_t width = ANativeWindow_getWidth(nativeWindow);
const int32_t height = ANativeWindow_getHeight(nativeWindow);
GLint maxTextureSize = 0;
GetGLContext()->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE,
(GLint*)&maxTextureSize);
// When window size is too big, hardware buffer allocation could fail.
if (maxTextureSize < width || maxTextureSize < height) {
gfxCriticalNote << "Too big ANativeWindow size(" << width << ", " << height
<< ") MaxTextureSize " << maxTextureSize;
return false;
}
mEGLSurface = CreateEGLSurface();
if (mEGLSurface == EGL_NO_SURFACE) {
RenderThread::Get()->HandleWebRenderError(WebRenderError::NEW_SURFACE);
return false;
}
gl::GLContextEGL::Cast(GetGLContext())->SetEGLSurfaceOverride(mEGLSurface);
mEGLSurfaceSize = Some(LayoutDeviceIntSize(width, height));
ANativeWindow_release(nativeWindow);
mCompositor->SetDestinationSurfaceSize(gfx::IntSize(width, height));
#elif defined(MOZ_WIDGET_GTK)
bool resumed = mCompositor->Resume();
if (!resumed) {
RenderThread::Get()->HandleWebRenderError(WebRenderError::NEW_SURFACE);
return false;
}
#endif
return true;
}
bool RenderCompositorOGLSWGL::IsPaused() {
#ifdef MOZ_WIDGET_ANDROID
return mEGLSurface == EGL_NO_SURFACE;
#endif
return false;
}
LayoutDeviceIntSize RenderCompositorOGLSWGL::GetBufferSize() {
if (mEGLSurfaceSize) {
return *mEGLSurfaceSize;
}
return mWidget->GetClientSize();
}
UniquePtr<RenderCompositorLayersSWGL::Tile>
RenderCompositorOGLSWGL::DoCreateTile(Surface* aSurface) {
const auto tileSize = aSurface->TileSize();
RefPtr<DataTextureSource> source = new TextureImageTextureSourceOGL(
mCompositor->AsCompositorOGL(), layers::TextureFlags::NO_FLAGS);
RefPtr<gfx::DataSourceSurface> surf = gfx::Factory::CreateDataSourceSurface(
gfx::IntSize(tileSize.width, tileSize.height),
gfx::SurfaceFormat::B8G8R8A8);
return MakeUnique<TileOGL>(source, surf);
}
bool RenderCompositorOGLSWGL::MaybeReadback(
const gfx::IntSize& aReadbackSize, const wr::ImageFormat& aReadbackFormat,
const Range<uint8_t>& aReadbackBuffer, bool* aNeedsYFlip) {
#ifdef MOZ_WIDGET_ANDROID
MOZ_ASSERT(aReadbackFormat == wr::ImageFormat::RGBA8);
const GLenum format = LOCAL_GL_RGBA;
#else
MOZ_ASSERT(aReadbackFormat == wr::ImageFormat::BGRA8);
const GLenum format = LOCAL_GL_BGRA;
#endif
GetGLContext()->fReadPixels(0, 0, aReadbackSize.width, aReadbackSize.height,
format, LOCAL_GL_UNSIGNED_BYTE,
&aReadbackBuffer[0]);
return true;
}
RenderCompositorOGLSWGL::TileOGL::TileOGL(layers::DataTextureSource* aTexture,
gfx::DataSourceSurface* aSurface)
: Tile(), mTexture(aTexture), mSurface(aSurface) {}
bool RenderCompositorOGLSWGL::TileOGL::Map(wr::DeviceIntRect aDirtyRect,
wr::DeviceIntRect aValidRect,
void** aData, int32_t* aStride) {
gfx::DataSourceSurface::MappedSurface map;
if (!mSurface->Map(gfx::DataSourceSurface::READ_WRITE, &map)) {
return false;
}
*aData =
map.mData + aValidRect.origin.y * map.mStride + aValidRect.origin.x * 4;
*aStride = map.mStride;
return true;
}
void RenderCompositorOGLSWGL::TileOGL::Unmap(const gfx::IntRect& aDirtyRect) {
mSurface->Unmap();
nsIntRegion dirty(aDirtyRect);
mTexture->Update(mSurface, &dirty);
}
} // namespace wr
} // namespace mozilla

View File

@@ -0,0 +1,82 @@
/* -*- 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/. */
#ifndef MOZILLA_GFX_RENDERCOMPOSITOR_OGL_SWGL_H
#define MOZILLA_GFX_RENDERCOMPOSITOR_OGL_SWGL_H
#include "mozilla/layers/Compositor.h"
#include "mozilla/webrender/RenderCompositorLayersSWGL.h"
namespace mozilla {
namespace wr {
class RenderCompositorOGLSWGL : public RenderCompositorLayersSWGL {
public:
static UniquePtr<RenderCompositor> Create(
RefPtr<widget::CompositorWidget>&& aWidget, nsACString& aError);
RenderCompositorOGLSWGL(layers::Compositor* aCompositor,
RefPtr<widget::CompositorWidget>&& aWidget,
void* aContext);
virtual ~RenderCompositorOGLSWGL();
gl::GLContext* GetGLContext();
bool MakeCurrent() override;
bool BeginFrame() override;
void Pause() override;
bool Resume() override;
bool IsPaused() override;
LayoutDeviceIntSize GetBufferSize() override;
layers::WebRenderCompositor CompositorType() const override {
return layers::WebRenderCompositor::OPENGL;
}
bool MaybeReadback(const gfx::IntSize& aReadbackSize,
const wr::ImageFormat& aReadbackFormat,
const Range<uint8_t>& aReadbackBuffer,
bool* aNeedsYFlip) override;
private:
void HandleExternalImage(RenderTextureHost* aExternalImage,
FrameSurface& aFrameSurface) override;
UniquePtr<RenderCompositorLayersSWGL::Tile> DoCreateTile(
Surface* aSurface) override;
EGLSurface CreateEGLSurface();
void DestroyEGLSurface();
EGLSurface mEGLSurface = EGL_NO_SURFACE;
// On android, we must track our own surface size.
Maybe<LayoutDeviceIntSize> mEGLSurfaceSize;
class TileOGL : public RenderCompositorLayersSWGL::Tile {
public:
TileOGL(layers::DataTextureSource* aTexture,
gfx::DataSourceSurface* aSurface);
virtual ~TileOGL() = default;
bool Map(wr::DeviceIntRect aDirtyRect, wr::DeviceIntRect aValidRect,
void** aData, int32_t* aStride) override;
void Unmap(const gfx::IntRect& aDirtyRect) override;
layers::DataTextureSource* GetTextureSource() override { return mTexture; }
bool IsValid() override { return true; }
private:
RefPtr<layers::DataTextureSource> mTexture;
RefPtr<gfx::DataSourceSurface> mSurface;
};
};
} // namespace wr
} // namespace mozilla
#endif

View File

@@ -24,6 +24,7 @@ class GLContext;
namespace wr {
class RenderAndroidSurfaceTextureHost;
class RenderCompositor;
class RenderDXGITextureHost;
class RenderDXGIYCbCrTextureHost;
@@ -81,6 +82,10 @@ class RenderTextureHost {
return nullptr;
}
virtual RenderAndroidSurfaceTextureHost* AsRenderAndroidSurfaceTextureHost() {
return nullptr;
}
virtual RenderTextureHostSWGL* AsRenderTextureHostSWGL() { return nullptr; }
protected:

View File

@@ -13,6 +13,7 @@ EXPORTS.mozilla.webrender += [
"RenderCompositorEGL.h",
"RenderCompositorLayersSWGL.h",
"RenderCompositorOGL.h",
"RenderCompositorOGLSWGL.h",
"RenderCompositorSWGL.h",
"RenderEGLImageTextureHost.h",
"RendererOGL.h",
@@ -35,6 +36,7 @@ UNIFIED_SOURCES += [
"RenderCompositorEGL.cpp",
"RenderCompositorLayersSWGL.cpp",
"RenderCompositorOGL.cpp",
"RenderCompositorOGLSWGL.cpp",
"RenderCompositorSWGL.cpp",
"RenderEGLImageTextureHost.cpp",
"RendererOGL.cpp",

View File

@@ -4874,6 +4874,11 @@
value: true
mirror: once
- name: gfx.webrender.software.opengl
type: bool
value: false
mirror: once
- name: gfx.webrender.software.d3d11.upload-mode
type: RelaxedAtomicInt32
value: 4