зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1598585 Part 4: Notify the content process of a canvas device change. r=jrmuizel
This sends a message to the content process on device reset/change. The content process clears the CanvasImageCache and canvas TextureClients and then records a new event, so the translator knows it has finished. Differential Revision: https://phabricator.services.mozilla.com/D60890 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
cad856864a
Коммит
a8de05ad4d
|
@ -155,17 +155,18 @@ class ImageCacheObserver final : public nsIObserver {
|
|||
|
||||
explicit ImageCacheObserver(ImageCache* aImageCache)
|
||||
: mImageCache(aImageCache) {
|
||||
RegisterMemoryPressureEvent();
|
||||
RegisterObserverEvents();
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
UnregisterMemoryPressureEvent();
|
||||
UnregisterObserverEvents();
|
||||
mImageCache = nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const char16_t* aSomeData) override {
|
||||
if (!mImageCache || strcmp(aTopic, "memory-pressure")) {
|
||||
if (!mImageCache || (strcmp(aTopic, "memory-pressure") != 0 &&
|
||||
strcmp(aTopic, "canvas-device-reset") != 0)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -176,7 +177,7 @@ class ImageCacheObserver final : public nsIObserver {
|
|||
private:
|
||||
virtual ~ImageCacheObserver() = default;
|
||||
|
||||
void RegisterMemoryPressureEvent() {
|
||||
void RegisterObserverEvents() {
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
|
@ -184,10 +185,11 @@ class ImageCacheObserver final : public nsIObserver {
|
|||
|
||||
if (observerService) {
|
||||
observerService->AddObserver(this, "memory-pressure", false);
|
||||
observerService->AddObserver(this, "canvas-device-reset", false);
|
||||
}
|
||||
}
|
||||
|
||||
void UnregisterMemoryPressureEvent() {
|
||||
void UnregisterObserverEvents() {
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
|
@ -196,6 +198,7 @@ class ImageCacheObserver final : public nsIObserver {
|
|||
// no longer available. See bug 1029504.
|
||||
if (observerService) {
|
||||
observerService->RemoveObserver(this, "memory-pressure");
|
||||
observerService->RemoveObserver(this, "canvas-device-reset");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -265,13 +265,13 @@ HTMLCanvasElementObserver::HTMLCanvasElementObserver(
|
|||
HTMLCanvasElement* aElement)
|
||||
: mElement(aElement) {
|
||||
RegisterVisibilityChangeEvent();
|
||||
RegisterMemoryPressureEvent();
|
||||
RegisterObserverEvents();
|
||||
}
|
||||
|
||||
HTMLCanvasElementObserver::~HTMLCanvasElementObserver() { Destroy(); }
|
||||
|
||||
void HTMLCanvasElementObserver::Destroy() {
|
||||
UnregisterMemoryPressureEvent();
|
||||
UnregisterObserverEvents();
|
||||
UnregisterVisibilityChangeEvent();
|
||||
mElement = nullptr;
|
||||
}
|
||||
|
@ -296,7 +296,7 @@ void HTMLCanvasElementObserver::UnregisterVisibilityChangeEvent() {
|
|||
this, true);
|
||||
}
|
||||
|
||||
void HTMLCanvasElementObserver::RegisterMemoryPressureEvent() {
|
||||
void HTMLCanvasElementObserver::RegisterObserverEvents() {
|
||||
if (!mElement) {
|
||||
return;
|
||||
}
|
||||
|
@ -306,11 +306,13 @@ void HTMLCanvasElementObserver::RegisterMemoryPressureEvent() {
|
|||
|
||||
MOZ_ASSERT(observerService);
|
||||
|
||||
if (observerService)
|
||||
if (observerService) {
|
||||
observerService->AddObserver(this, "memory-pressure", false);
|
||||
observerService->AddObserver(this, "canvas-device-reset", false);
|
||||
}
|
||||
}
|
||||
|
||||
void HTMLCanvasElementObserver::UnregisterMemoryPressureEvent() {
|
||||
void HTMLCanvasElementObserver::UnregisterObserverEvents() {
|
||||
if (!mElement) {
|
||||
return;
|
||||
}
|
||||
|
@ -321,17 +323,24 @@ void HTMLCanvasElementObserver::UnregisterMemoryPressureEvent() {
|
|||
// Do not assert on observerService here. This might be triggered by
|
||||
// the cycle collector at a late enough time, that XPCOM services are
|
||||
// no longer available. See bug 1029504.
|
||||
if (observerService) observerService->RemoveObserver(this, "memory-pressure");
|
||||
if (observerService) {
|
||||
observerService->RemoveObserver(this, "memory-pressure");
|
||||
observerService->RemoveObserver(this, "canvas-device-reset");
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLCanvasElementObserver::Observe(nsISupports*, const char* aTopic,
|
||||
const char16_t*) {
|
||||
if (!mElement || strcmp(aTopic, "memory-pressure")) {
|
||||
if (!mElement) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mElement->OnMemoryPressure();
|
||||
if (strcmp(aTopic, "memory-pressure") == 0) {
|
||||
mElement->OnMemoryPressure();
|
||||
} else if (strcmp(aTopic, "canvas-device-reset") == 0) {
|
||||
mElement->OnDeviceReset();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -399,7 +408,8 @@ HTMLCanvasElement::CreateContext(CanvasContextType aContextType) {
|
|||
|
||||
// Add Observer for webgl canvas.
|
||||
if (aContextType == CanvasContextType::WebGL1 ||
|
||||
aContextType == CanvasContextType::WebGL2) {
|
||||
aContextType == CanvasContextType::WebGL2 ||
|
||||
aContextType == CanvasContextType::Canvas2D) {
|
||||
if (!mContextObserver) {
|
||||
mContextObserver = new HTMLCanvasElementObserver(this);
|
||||
}
|
||||
|
@ -1445,6 +1455,12 @@ void HTMLCanvasElement::OnMemoryPressure() {
|
|||
}
|
||||
}
|
||||
|
||||
void HTMLCanvasElement::OnDeviceReset() {
|
||||
if (!mOffscreenCanvas && mCurrentContext) {
|
||||
mCurrentContext->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
void HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(
|
||||
AsyncCanvasRenderer* aRenderer) {
|
||||
|
|
|
@ -69,8 +69,8 @@ class HTMLCanvasElementObserver final : public nsIObserver,
|
|||
void RegisterVisibilityChangeEvent();
|
||||
void UnregisterVisibilityChangeEvent();
|
||||
|
||||
void RegisterMemoryPressureEvent();
|
||||
void UnregisterMemoryPressureEvent();
|
||||
void RegisterObserverEvents();
|
||||
void UnregisterObserverEvents();
|
||||
|
||||
private:
|
||||
~HTMLCanvasElementObserver();
|
||||
|
@ -328,6 +328,8 @@ class HTMLCanvasElement final : public nsGenericHTMLElement,
|
|||
|
||||
void OnMemoryPressure();
|
||||
|
||||
void OnDeviceReset();
|
||||
|
||||
static void SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer* aRenderer);
|
||||
static void InvalidateFromAsyncCanvasRenderer(AsyncCanvasRenderer* aRenderer);
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ const EventType PREPARE_DATA_FOR_SURFACE = EventType(EventType::LAST + 6);
|
|||
const EventType GET_DATA_FOR_SURFACE = EventType(EventType::LAST + 7);
|
||||
const EventType ADD_SURFACE_ALIAS = EventType(EventType::LAST + 8);
|
||||
const EventType REMOVE_SURFACE_ALIAS = EventType(EventType::LAST + 9);
|
||||
const EventType DEVICE_CHANGE_ACKNOWLEDGED = EventType(EventType::LAST + 10);
|
||||
|
||||
class RecordedCanvasBeginTransaction final
|
||||
: public RecordedEventDerived<RecordedCanvasBeginTransaction> {
|
||||
|
@ -461,6 +462,38 @@ RecordedRemoveSurfaceAlias::RecordedRemoveSurfaceAlias(S& aStream)
|
|||
ReadElement(aStream, mSurfaceAlias);
|
||||
}
|
||||
|
||||
class RecordedDeviceChangeAcknowledged final
|
||||
: public RecordedEventDerived<RecordedDeviceChangeAcknowledged> {
|
||||
public:
|
||||
RecordedDeviceChangeAcknowledged()
|
||||
: RecordedEventDerived(DEVICE_CHANGE_ACKNOWLEDGED) {}
|
||||
|
||||
template <class S>
|
||||
MOZ_IMPLICIT RecordedDeviceChangeAcknowledged(S& aStream);
|
||||
|
||||
bool PlayCanvasEvent(CanvasTranslator* aTranslator) const;
|
||||
|
||||
template <class S>
|
||||
void Record(S& aStream) const;
|
||||
|
||||
std::string GetName() const final {
|
||||
return "RecordedDeviceChangeAcknowledged";
|
||||
}
|
||||
};
|
||||
|
||||
inline bool RecordedDeviceChangeAcknowledged::PlayCanvasEvent(
|
||||
CanvasTranslator* aTranslator) const {
|
||||
aTranslator->DeviceChangeAcknowledged();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class S>
|
||||
void RecordedDeviceChangeAcknowledged::Record(S& aStream) const {}
|
||||
|
||||
template <class S>
|
||||
RecordedDeviceChangeAcknowledged::RecordedDeviceChangeAcknowledged(S& aStream)
|
||||
: RecordedEventDerived(DEVICE_CHANGE_ACKNOWLEDGED) {}
|
||||
|
||||
#define FOR_EACH_CANVAS_EVENT(f) \
|
||||
f(CANVAS_BEGIN_TRANSACTION, RecordedCanvasBeginTransaction); \
|
||||
f(CANVAS_END_TRANSACTION, RecordedCanvasEndTransaction); \
|
||||
|
@ -471,7 +504,8 @@ RecordedRemoveSurfaceAlias::RecordedRemoveSurfaceAlias(S& aStream)
|
|||
f(PREPARE_DATA_FOR_SURFACE, RecordedPrepareDataForSurface); \
|
||||
f(GET_DATA_FOR_SURFACE, RecordedGetDataForSurface); \
|
||||
f(ADD_SURFACE_ALIAS, RecordedAddSurfaceAlias); \
|
||||
f(REMOVE_SURFACE_ALIAS, RecordedRemoveSurfaceAlias);
|
||||
f(REMOVE_SURFACE_ALIAS, RecordedRemoveSurfaceAlias); \
|
||||
f(DEVICE_CHANGE_ACKNOWLEDGED, RecordedDeviceChangeAcknowledged);
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "mozilla/gfx/Rect.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include "mozilla/layers/CanvasDrawEventRecorder.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "RecordedCanvasEventImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -112,6 +113,16 @@ CanvasChild::CanvasChild(Endpoint<PCanvasChild>&& aEndpoint) {
|
|||
|
||||
CanvasChild::~CanvasChild() {}
|
||||
|
||||
ipc::IPCResult CanvasChild::RecvNotifyDeviceChanged() {
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->NotifyObservers(nullptr, "canvas-device-reset", nullptr);
|
||||
}
|
||||
|
||||
mRecorder->RecordEvent(RecordedDeviceChangeAcknowledged());
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void CanvasChild::EnsureRecorder(TextureType aTextureType) {
|
||||
if (!mRecorder) {
|
||||
MOZ_ASSERT(mTextureType == TextureType::Unknown);
|
||||
|
|
|
@ -29,6 +29,8 @@ class CanvasChild final : public PCanvasChild {
|
|||
|
||||
explicit CanvasChild(Endpoint<PCanvasChild>&& aEndpoint);
|
||||
|
||||
ipc::IPCResult RecvNotifyDeviceChanged();
|
||||
|
||||
/**
|
||||
* Ensures that the DrawEventRecorder has been created.
|
||||
*
|
||||
|
|
|
@ -197,7 +197,13 @@ bool CanvasTranslator::TranslateRecording() {
|
|||
});
|
||||
|
||||
if (!success && !HandleExtensionEvent(eventType)) {
|
||||
gfxCriticalNote << "Failed to play canvas event type: " << eventType;
|
||||
if (mDeviceResetInProgress) {
|
||||
// We've notified the recorder of a device change, so we are expecting
|
||||
// failures. Log as a warning to prevent crash reporting being flooded.
|
||||
gfxWarning() << "Failed to play canvas event type: " << eventType;
|
||||
} else {
|
||||
gfxCriticalNote << "Failed to play canvas event type: " << eventType;
|
||||
}
|
||||
if (!mStream->good()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -262,11 +268,19 @@ void CanvasTranslator::EndTransaction() {
|
|||
mIsInTransaction = false;
|
||||
}
|
||||
|
||||
void CanvasTranslator::DeviceChangeAcknowledged() {
|
||||
mDeviceResetInProgress = false;
|
||||
}
|
||||
|
||||
bool CanvasTranslator::CheckForFreshCanvasDevice(int aLineNumber) {
|
||||
#if defined(XP_WIN)
|
||||
// If a new device has already been created, use that one.
|
||||
RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetCanvasDevice();
|
||||
if (device && device != mDevice) {
|
||||
if (mDevice) {
|
||||
// We already had a device, notify child of change.
|
||||
NotifyDeviceChanged();
|
||||
}
|
||||
mDevice = device.forget();
|
||||
return true;
|
||||
}
|
||||
|
@ -278,6 +292,7 @@ bool CanvasTranslator::CheckForFreshCanvasDevice(int aLineNumber) {
|
|||
|
||||
gfxCriticalNote << "GFX: CanvasTranslator detected a device reset at "
|
||||
<< aLineNumber;
|
||||
NotifyDeviceChanged();
|
||||
}
|
||||
|
||||
RefPtr<Runnable> runnable = NS_NewRunnableFunction(
|
||||
|
@ -296,6 +311,13 @@ bool CanvasTranslator::CheckForFreshCanvasDevice(int aLineNumber) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void CanvasTranslator::NotifyDeviceChanged() {
|
||||
mDeviceResetInProgress = true;
|
||||
mCanvasThreadHolder->DispatchToCanvasThread(
|
||||
NewRunnableMethod("CanvasTranslator::SendNotifyDeviceChanged", this,
|
||||
&CanvasTranslator::SendNotifyDeviceChanged));
|
||||
}
|
||||
|
||||
void CanvasTranslator::AddSurfaceDescriptor(gfx::ReferencePtr aRefPtr,
|
||||
TextureData* aTextureData) {
|
||||
UniquePtr<SurfaceDescriptor> descriptor = MakeUnique<SurfaceDescriptor>();
|
||||
|
|
|
@ -127,6 +127,11 @@ class CanvasTranslator final : public gfx::InlineTranslator,
|
|||
*/
|
||||
void Flush();
|
||||
|
||||
/**
|
||||
* Marks that device change processing in the writing process has finished.
|
||||
*/
|
||||
void DeviceChangeAcknowledged();
|
||||
|
||||
/**
|
||||
* Used to send data back to the writer. This is done through the same shared
|
||||
* memory so the writer must wait and read the response after it has submitted
|
||||
|
@ -259,6 +264,7 @@ class CanvasTranslator final : public gfx::InlineTranslator,
|
|||
bool HandleExtensionEvent(int32_t aType);
|
||||
|
||||
bool CheckForFreshCanvasDevice(int aLineNumber);
|
||||
void NotifyDeviceChanged();
|
||||
|
||||
RefPtr<CanvasThreadHolder> mCanvasThreadHolder;
|
||||
RefPtr<TaskQueue> mTranslationTaskQueue;
|
||||
|
@ -281,6 +287,7 @@ class CanvasTranslator final : public gfx::InlineTranslator,
|
|||
"CanvasTranslator::mSurfaceDescriptorsMonitor"};
|
||||
bool mIsValid = true;
|
||||
bool mIsInTransaction = false;
|
||||
bool mDeviceResetInProgress = false;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -31,6 +31,12 @@ parent:
|
|||
* stopped due to a timeout waiting for events.
|
||||
*/
|
||||
async ResumeTranslation();
|
||||
|
||||
child:
|
||||
/**
|
||||
* Notify that the canvas device used by the translator has changed.
|
||||
*/
|
||||
async NotifyDeviceChanged();
|
||||
};
|
||||
|
||||
} // layers
|
||||
|
|
Загрузка…
Ссылка в новой задаче