Bug 1630521: Allow CanvasDrawEventRecorder to control surface destruction recording, so it can be done on the main thread. r=jrmuizel
authorBob Owen <bobowencode@gmail.com>
Thu, 16 Apr 2020 17:13:16 +0000
changeset 524440 8df5d0174680b9036c340d96402794bf72be05f1
parent 524439 b8498a40239851aa3fd8d15561b3234b20aa975f
child 524441 b411dd8c786a56c51c3e3c31d293358fa2038b69
push id37321
push userdluca@mozilla.com
push dateFri, 17 Apr 2020 09:38:52 +0000
treeherdermozilla-central@24537fed53e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1630521
milestone77.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1630521: Allow CanvasDrawEventRecorder to control surface destruction recording, so it can be done on the main thread. r=jrmuizel The recording by CanvasDrawEventRecorder into the ring buffer is not thread-safe and so must all occur on the same (main) thread. In addition to that it sometimes needs to send IPC messages via the PCanvas protocol, which also can only be done on the main thread. Differential Revision: https://phabricator.services.mozilla.com/D71174
gfx/2d/DrawEventRecorder.cpp
gfx/2d/DrawEventRecorder.h
gfx/2d/DrawTargetRecording.cpp
gfx/2d/DrawTargetWrapAndRecord.cpp
gfx/layers/CanvasDrawEventRecorder.cpp
gfx/layers/CanvasDrawEventRecorder.h
--- a/gfx/2d/DrawEventRecorder.cpp
+++ b/gfx/2d/DrawEventRecorder.cpp
@@ -43,16 +43,23 @@ void DrawEventRecorderPrivate::StoreSour
   }
 
   DataSourceSurface::ScopedMap map(dataSurf, DataSourceSurface::READ);
   RecordEvent(RecordedSourceSurfaceCreation(
       aSurface, map.GetData(), map.GetStride(), dataSurf->GetSize(),
       dataSurf->GetFormat()));
 }
 
+void DrawEventRecorderPrivate::RecordSourceSurfaceDestruction(
+    SourceSurface* aSurface) {
+  RemoveSourceSurface(aSurface);
+  RemoveStoredObject(aSurface);
+  RecordEvent(RecordedSourceSurfaceDestruction(ReferencePtr(aSurface)));
+}
+
 void DrawEventRecorderFile::RecordEvent(const RecordedEvent& aEvent) {
   aEvent.RecordToStream(mOutputStream);
 
   Flush();
 }
 
 void DrawEventRecorderMemory::RecordEvent(const RecordedEvent& aEvent) {
   aEvent.RecordToStream(mOutputStream);
--- a/gfx/2d/DrawEventRecorder.h
+++ b/gfx/2d/DrawEventRecorder.h
@@ -119,16 +119,18 @@ class DrawEventRecorderPrivate : public 
 
   void TakeExternalSurfaces(std::vector<RefPtr<SourceSurface>>& aSurfaces) {
     aSurfaces = std::move(mExternalSurfaces);
   }
 
   virtual void StoreSourceSurfaceRecording(SourceSurface* aSurface,
                                            const char* aReason);
 
+  virtual void RecordSourceSurfaceDestruction(SourceSurface* aSurface);
+
   virtual void AddDependentSurface(uint64_t aDependencyId) {
     MOZ_CRASH("GFX: AddDependentSurface");
   }
 
  protected:
   void StoreExternalSurfaceRecording(SourceSurface* aSurface, uint64_t aKey);
 
   virtual void Flush() = 0;
--- a/gfx/2d/DrawTargetRecording.cpp
+++ b/gfx/2d/DrawTargetRecording.cpp
@@ -26,20 +26,18 @@ struct RecordingSourceSurfaceUserData {
   void* refPtr;
   RefPtr<DrawEventRecorderPrivate> recorder;
 };
 
 static void RecordingSourceSurfaceUserDataFunc(void* aUserData) {
   RecordingSourceSurfaceUserData* userData =
       static_cast<RecordingSourceSurfaceUserData*>(aUserData);
 
-  userData->recorder->RemoveSourceSurface((SourceSurface*)userData->refPtr);
-  userData->recorder->RemoveStoredObject(userData->refPtr);
-  userData->recorder->RecordEvent(
-      RecordedSourceSurfaceDestruction(ReferencePtr(userData->refPtr)));
+  userData->recorder->RecordSourceSurfaceDestruction(
+      static_cast<SourceSurface*>(userData->refPtr));
 
   delete userData;
 }
 
 static void EnsureSurfaceStoredRecording(DrawEventRecorderPrivate* aRecorder,
                                          SourceSurface* aSurface,
                                          const char* reason) {
   if (aRecorder->HasStoredObject(aSurface)) {
--- a/gfx/2d/DrawTargetWrapAndRecord.cpp
+++ b/gfx/2d/DrawTargetWrapAndRecord.cpp
@@ -22,20 +22,18 @@ struct WrapAndRecordSourceSurfaceUserDat
   void* refPtr;
   RefPtr<DrawEventRecorderPrivate> recorder;
 };
 
 static void WrapAndRecordSourceSurfaceUserDataFunc(void* aUserData) {
   WrapAndRecordSourceSurfaceUserData* userData =
       static_cast<WrapAndRecordSourceSurfaceUserData*>(aUserData);
 
-  userData->recorder->RemoveSourceSurface((SourceSurface*)userData->refPtr);
-  userData->recorder->RemoveStoredObject(userData->refPtr);
-  userData->recorder->RecordEvent(
-      RecordedSourceSurfaceDestruction(ReferencePtr(userData->refPtr)));
+  userData->recorder->RecordSourceSurfaceDestruction(
+      static_cast<SourceSurface*>(userData->refPtr));
 
   delete userData;
 }
 
 static void StoreSourceSurface(DrawEventRecorderPrivate* aRecorder,
                                SourceSurface* aSurface,
                                DataSourceSurface* aDataSurf,
                                const char* reason) {
--- a/gfx/layers/CanvasDrawEventRecorder.cpp
+++ b/gfx/layers/CanvasDrawEventRecorder.cpp
@@ -3,16 +3,18 @@
 /* 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 "CanvasDrawEventRecorder.h"
 
 #include <string.h>
 
+#include "nsThreadUtils.h"
+
 namespace mozilla {
 namespace layers {
 
 static const int32_t kCheckpointEventType = -1;
 static const uint32_t kMaxSpinCount = 200;
 
 static const TimeDuration kTimeout = TimeDuration::FromMilliseconds(100);
 static const int32_t kTimeoutRetryCount = 50;
@@ -484,10 +486,24 @@ void CanvasEventRingBuffer::ReturnRead(c
     availableToRead = std::min(bufRemaining, (mRead->returnCount - readCount));
   }
 
   memcpy(aOut, mBuf + bufPos, aSize);
   readCount += aSize;
   mWrite->returnCount = readCount;
 }
 
+void CanvasDrawEventRecorder::RecordSourceSurfaceDestruction(
+    gfx::SourceSurface* aSurface) {
+  // We must only record things on the main thread and surfaces that have been
+  // recorded can sometimes be destroyed off the main thread.
+  if (NS_IsMainThread()) {
+    DrawEventRecorderPrivate::RecordSourceSurfaceDestruction(aSurface);
+    return;
+  }
+
+  NS_DispatchToMainThread(NewRunnableMethod<gfx::SourceSurface*>(
+      "DrawEventRecorderPrivate::RecordSourceSurfaceDestruction", this,
+      &DrawEventRecorderPrivate::RecordSourceSurfaceDestruction, aSurface));
+}
+
 }  // namespace layers
 }  // namespace mozilla
--- a/gfx/layers/CanvasDrawEventRecorder.h
+++ b/gfx/layers/CanvasDrawEventRecorder.h
@@ -242,16 +242,18 @@ class CanvasDrawEventRecorder final : pu
   void RecordEvent(const gfx::RecordedEvent& aEvent) final {
     if (!mOutputStream.good()) {
       return;
     }
 
     aEvent.RecordToStream(mOutputStream);
   }
 
+  void RecordSourceSurfaceDestruction(gfx::SourceSurface* aSurface) final;
+
   void Flush() final {}
 
   void ReturnRead(char* aOut, size_t aSize) {
     mOutputStream.ReturnRead(aOut, aSize);
   }
 
   uint32_t CreateCheckpoint() { return mOutputStream.CreateCheckpoint(); }