forked from mirrors/gecko-dev
In bug 1772839 we were seeing a large number of crashes due to encountering a webrender error after exhausting all fallback configurations. At least in some cases, this was due to the compositor being resumed with an Android Surface that was already in an abandoned state, meaning we can never succeed in creating an EGL Surface. We added a check for this condition, and a workaround, to the GeckoView java code. However, we are still seeing crash reports matching this signature. To help determine whether these are also due to the Surface being abandoned, or due to some other reason, this patch adds a deliberate crash much earlier in the pipeline if we detect an abandoned Surface. Differential Revision: https://phabricator.services.mozilla.com/D160042
113 lines
3.5 KiB
C++
113 lines
3.5 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set sw=2 ts=2 et 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 "AndroidCompositorWidget.h"
|
|
|
|
#include "mozilla/gfx/Logging.h"
|
|
#include "mozilla/widget/PlatformWidgetTypes.h"
|
|
#include "nsWindow.h"
|
|
#include "SurfaceViewWrapperSupport.h"
|
|
|
|
namespace mozilla {
|
|
namespace widget {
|
|
|
|
AndroidCompositorWidget::AndroidCompositorWidget(
|
|
const AndroidCompositorWidgetInitData& aInitData,
|
|
const layers::CompositorOptions& aOptions)
|
|
: CompositorWidget(aOptions),
|
|
mWidgetId(aInitData.widgetId()),
|
|
mNativeWindow(nullptr),
|
|
mFormat(WINDOW_FORMAT_RGBA_8888),
|
|
mClientSize(aInitData.clientSize()) {}
|
|
|
|
AndroidCompositorWidget::~AndroidCompositorWidget() {
|
|
if (mNativeWindow) {
|
|
ANativeWindow_release(mNativeWindow);
|
|
}
|
|
}
|
|
|
|
already_AddRefed<gfx::DrawTarget>
|
|
AndroidCompositorWidget::StartRemoteDrawingInRegion(
|
|
const LayoutDeviceIntRegion& aInvalidRegion,
|
|
layers::BufferMode* aBufferMode) {
|
|
if (!mNativeWindow) {
|
|
EGLNativeWindowType window = GetEGLNativeWindow();
|
|
JNIEnv* const env = jni::GetEnvForThread();
|
|
mNativeWindow =
|
|
ANativeWindow_fromSurface(env, reinterpret_cast<jobject>(window));
|
|
if (mNativeWindow) {
|
|
mFormat = ANativeWindow_getFormat(mNativeWindow);
|
|
ANativeWindow_acquire(mNativeWindow);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
if (mFormat != WINDOW_FORMAT_RGBA_8888 &&
|
|
mFormat != WINDOW_FORMAT_RGBX_8888) {
|
|
gfxCriticalNoteOnce << "Non supported format: " << mFormat;
|
|
return nullptr;
|
|
}
|
|
|
|
// XXX Handle inOutDirtyBounds
|
|
if (ANativeWindow_lock(mNativeWindow, &mBuffer, nullptr) != 0) {
|
|
return nullptr;
|
|
}
|
|
|
|
const int bpp = 4;
|
|
gfx::SurfaceFormat format = gfx::SurfaceFormat::R8G8B8A8;
|
|
if (mFormat == WINDOW_FORMAT_RGBX_8888) {
|
|
format = gfx::SurfaceFormat::R8G8B8X8;
|
|
}
|
|
|
|
RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateDrawTargetForData(
|
|
gfx::BackendType::SKIA, static_cast<unsigned char*>(mBuffer.bits),
|
|
gfx::IntSize(mBuffer.width, mBuffer.height), mBuffer.stride * bpp, format,
|
|
true);
|
|
|
|
return dt.forget();
|
|
}
|
|
|
|
void AndroidCompositorWidget::EndRemoteDrawingInRegion(
|
|
gfx::DrawTarget* aDrawTarget, const LayoutDeviceIntRegion& aInvalidRegion) {
|
|
ANativeWindow_unlockAndPost(mNativeWindow);
|
|
}
|
|
|
|
bool AndroidCompositorWidget::OnResumeComposition() {
|
|
OnCompositorSurfaceChanged();
|
|
|
|
if (!mSurface) {
|
|
gfxCriticalError() << "OnResumeComposition called with null Surface";
|
|
return false;
|
|
}
|
|
|
|
// If our Surface is in an abandoned state then we will never succesfully
|
|
// create an EGL Surface, and will eventually crash. Better to explicitly
|
|
// crash now.
|
|
if (SurfaceViewWrapperSupport::IsSurfaceAbandoned(mSurface)) {
|
|
MOZ_CRASH("Compositor resumed with abandoned Surface");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
EGLNativeWindowType AndroidCompositorWidget::GetEGLNativeWindow() {
|
|
return (EGLNativeWindowType)mSurface.Get();
|
|
}
|
|
|
|
LayoutDeviceIntSize AndroidCompositorWidget::GetClientSize() {
|
|
return mClientSize;
|
|
}
|
|
|
|
void AndroidCompositorWidget::NotifyClientSizeChanged(
|
|
const LayoutDeviceIntSize& aClientSize) {
|
|
mClientSize =
|
|
LayoutDeviceIntSize(std::min(aClientSize.width, MOZ_WIDGET_MAX_SIZE),
|
|
std::min(aClientSize.height, MOZ_WIDGET_MAX_SIZE));
|
|
}
|
|
|
|
} // namespace widget
|
|
} // namespace mozilla
|