From 2838c9d2fa8602361121f5478d8766d39b3ab737 Mon Sep 17 00:00:00 2001 From: Bren Louis Date: Thu, 6 Jun 2019 23:01:01 +0800 Subject: [PATCH 01/22] Bug 1514372 - Removed time record regarding TELEMETRY_MEMORY_REPORTER_MS r=chutten --- toolkit/components/telemetry/Histograms.json | 9 --------- toolkit/components/telemetry/histogram-whitelists.json | 1 - xpcom/base/MemoryTelemetry.cpp | 5 ----- 3 files changed, 15 deletions(-) diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index a2263255de78..bbfe85c7a329 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -8396,15 +8396,6 @@ "n_buckets": 15, "description": "Time (ms) it takes to figure out extension last modified time" }, - "TELEMETRY_MEMORY_REPORTER_MS": { - "record_in_processes": ["main", "content"], - "alert_emails": ["memshrink-telemetry-alerts@mozilla.com"], - "expires_in_version": "never", - "kind": "exponential", - "high": 5000, - "n_buckets": 10, - "description": "Time (ms) it takes to run memory reporters when sending a telemetry ping" - }, "SSL_SUCCESFUL_CERT_VALIDATION_TIME_MOZILLAPKIX" : { "record_in_processes": ["main", "content"], "alert_emails": ["seceng-telemetry@mozilla.com"], diff --git a/toolkit/components/telemetry/histogram-whitelists.json b/toolkit/components/telemetry/histogram-whitelists.json index 701306b3a113..99294c91efc2 100644 --- a/toolkit/components/telemetry/histogram-whitelists.json +++ b/toolkit/components/telemetry/histogram-whitelists.json @@ -1053,7 +1053,6 @@ "TELEMETRY_DISCARDED_PENDING_PINGS_SIZE_MB", "TELEMETRY_DISCARDED_SEND_PINGS_SIZE_MB", "TELEMETRY_INVALID_PING_TYPE_SUBMITTED", - "TELEMETRY_MEMORY_REPORTER_MS", "TELEMETRY_PENDING_CHECKING_OVER_QUOTA_MS", "TELEMETRY_PENDING_EVICTING_OVER_QUOTA_MS", "TELEMETRY_PENDING_LOAD_FAILURE_PARSE", diff --git a/xpcom/base/MemoryTelemetry.cpp b/xpcom/base/MemoryTelemetry.cpp index e90d126bd580..0d5840ded8cd 100644 --- a/xpcom/base/MemoryTelemetry.cpp +++ b/xpcom/base/MemoryTelemetry.cpp @@ -231,8 +231,6 @@ nsresult MemoryTelemetry::GatherReports( MOZ_DIAGNOSTIC_ASSERT(mgr); NS_ENSURE_TRUE(mgr, NS_ERROR_FAILURE); - auto startTime = TimeStamp::Now(); - #define RECORD(id, metric, units) \ do { \ int64_t amt; \ @@ -332,9 +330,6 @@ nsresult MemoryTelemetry::GatherReports( mTotalMemoryGatherer->Begin(mThreadPool); } - Telemetry::AccumulateTimeDelta( - Telemetry::HistogramID::TELEMETRY_MEMORY_REPORTER_MS, startTime, - TimeStamp::Now()); return NS_OK; } From 42709ab870d7dfd81d98746ea441c71acad2b8c6 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Thu, 21 Feb 2019 11:23:00 +0000 Subject: [PATCH 02/22] Bug 1529677 - Move writing of Event type from RecordEvent() into RecordToStream(). r=bobowen --- gfx/2d/DrawEventRecorder.cpp | 4 ---- gfx/2d/RecordedEventImpl.h | 6 ++++++ layout/printing/DrawEventRecorder.cpp | 2 -- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gfx/2d/DrawEventRecorder.cpp b/gfx/2d/DrawEventRecorder.cpp index bed456c82605..dee5d42f6d3a 100644 --- a/gfx/2d/DrawEventRecorder.cpp +++ b/gfx/2d/DrawEventRecorder.cpp @@ -45,16 +45,12 @@ void DrawEventRecorderPrivate::StoreSourceSurfaceRecording( } void DrawEventRecorderFile::RecordEvent(const RecordedEvent& aEvent) { - WriteElement(mOutputStream, aEvent.mType); - aEvent.RecordToStream(mOutputStream); Flush(); } void DrawEventRecorderMemory::RecordEvent(const RecordedEvent& aEvent) { - WriteElement(mOutputStream, aEvent.mType); - aEvent.RecordToStream(mOutputStream); } diff --git a/gfx/2d/RecordedEventImpl.h b/gfx/2d/RecordedEventImpl.h index ef1b0c03216b..09e27de02cf8 100644 --- a/gfx/2d/RecordedEventImpl.h +++ b/gfx/2d/RecordedEventImpl.h @@ -26,16 +26,22 @@ class RecordedEventDerived : public RecordedEvent { public: void RecordToStream(std::ostream& aStream) const override { + WriteElement(aStream, this->mType); static_cast(this)->Record(aStream); } void RecordToStream(EventStream& aStream) const override { + WriteElement(aStream, this->mType); static_cast(this)->Record(aStream); } void RecordToStream(MemStream& aStream) const override { SizeCollector size; + WriteElement(size, this->mType); static_cast(this)->Record(size); + aStream.Resize(aStream.mLength + size.mTotalSize); + MemWriter writer(aStream.mData + aStream.mLength - size.mTotalSize); + WriteElement(writer, this->mType); static_cast(this)->Record(writer); } }; diff --git a/layout/printing/DrawEventRecorder.cpp b/layout/printing/DrawEventRecorder.cpp index 7db75d8fe299..9f993152c483 100644 --- a/layout/printing/DrawEventRecorder.cpp +++ b/layout/printing/DrawEventRecorder.cpp @@ -11,8 +11,6 @@ namespace layout { void DrawEventRecorderPRFileDesc::RecordEvent( const gfx::RecordedEvent& aEvent) { - WriteElement(mOutputStream, aEvent.GetType()); - aEvent.RecordToStream(mOutputStream); Flush(); From fd4b37602b3cef069dca46824335da03b8819bc2 Mon Sep 17 00:00:00 2001 From: Bob Owen Date: Sun, 2 Dec 2018 14:02:27 +0000 Subject: [PATCH 03/22] Bug 1464032 Part 1: Fix unified build issues. r=jrmuizel --- gfx/layers/ProfilerScreenshots.cpp | 2 ++ gfx/layers/ProfilerScreenshots.h | 9 ++++++--- gfx/layers/apz/src/APZCTreeManager.h | 1 + gfx/layers/basic/BasicCompositor.cpp | 1 + gfx/layers/composite/CompositableHost.cpp | 1 + gfx/layers/composite/CompositorScreenshotGrabber.cpp | 2 ++ gfx/layers/composite/CompositorScreenshotGrabber.h | 1 + gfx/layers/composite/TiledContentHost.cpp | 1 + gfx/layers/d3d11/MLGDeviceD3D11.cpp | 2 ++ gfx/layers/d3d11/TextureD3D11.cpp | 2 ++ gfx/layers/ipc/CompositorBridgeParent.cpp | 6 +++--- gfx/layers/ipc/ContentCompositorBridgeParent.cpp | 12 ++++++++---- gfx/layers/ipc/ImageBridgeChild.cpp | 1 + gfx/layers/ipc/UiCompositorControllerParent.cpp | 2 ++ gfx/layers/wr/RenderRootStateManager.cpp | 1 + gfx/layers/wr/WebRenderBridgeParent.h | 1 + gfx/layers/wr/WebRenderCommandBuilder.cpp | 1 + gfx/webrender_bindings/WebRenderAPI.h | 1 + 18 files changed, 37 insertions(+), 10 deletions(-) diff --git a/gfx/layers/ProfilerScreenshots.cpp b/gfx/layers/ProfilerScreenshots.cpp index ec5a3af6062d..220c500b3e5c 100644 --- a/gfx/layers/ProfilerScreenshots.cpp +++ b/gfx/layers/ProfilerScreenshots.cpp @@ -6,6 +6,7 @@ #include "mozilla/layers/ProfilerScreenshots.h" +#include "mozilla/SystemGroup.h" #include "mozilla/TimeStamp.h" #include "GeckoProfiler.h" @@ -16,6 +17,7 @@ #endif using namespace mozilla; +using namespace mozilla::gfx; using namespace mozilla::layers; ProfilerScreenshots::ProfilerScreenshots() diff --git a/gfx/layers/ProfilerScreenshots.h b/gfx/layers/ProfilerScreenshots.h index f0b216f99749..08e51958caa4 100644 --- a/gfx/layers/ProfilerScreenshots.h +++ b/gfx/layers/ProfilerScreenshots.h @@ -11,6 +11,9 @@ #include "mozilla/Mutex.h" #include "mozilla/RefPtr.h" +#include "mozilla/TimeStamp.h" +#include "nsCOMPtr.h" +#include "nsTArray.h" #include "mozilla/gfx/Point.h" @@ -84,19 +87,19 @@ class ProfilerScreenshots final { * Returns null if the limit is reached. * Can be called on any thread. */ - already_AddRefed TakeNextSurface(); + already_AddRefed TakeNextSurface(); /** * Return aSurface back into the mAvailableSurfaces pool. Can be called on * any thread. */ - void ReturnSurface(DataSourceSurface* aSurface); + void ReturnSurface(gfx::DataSourceSurface* aSurface); // The thread on which encoding happens. nsCOMPtr mThread; // An array of surfaces ready to be recycled. Can be accessed from multiple // threads, protected by mMutex. - nsTArray> mAvailableSurfaces; + nsTArray> mAvailableSurfaces; // Protects mAvailableSurfaces. Mutex mMutex; // The total number of surfaces created. If encoding is fast enough to happen diff --git a/gfx/layers/apz/src/APZCTreeManager.h b/gfx/layers/apz/src/APZCTreeManager.h index b3a4d00c7ced..b8a94bc21783 100644 --- a/gfx/layers/apz/src/APZCTreeManager.h +++ b/gfx/layers/apz/src/APZCTreeManager.h @@ -18,6 +18,7 @@ #include "mozilla/layers/APZInputBridge.h" // for APZInputBridge #include "mozilla/layers/APZTestData.h" // for APZTestData #include "mozilla/layers/IAPZCTreeManager.h" // for IAPZCTreeManager +#include "mozilla/layers/LayerAttributes.h" #include "mozilla/layers/LayersTypes.h" #include "mozilla/layers/KeyboardMap.h" // for KeyboardMap #include "mozilla/layers/TouchCounter.h" // for TouchCounter diff --git a/gfx/layers/basic/BasicCompositor.cpp b/gfx/layers/basic/BasicCompositor.cpp index c1546edd3a0e..a348c5ac47d9 100644 --- a/gfx/layers/basic/BasicCompositor.cpp +++ b/gfx/layers/basic/BasicCompositor.cpp @@ -19,6 +19,7 @@ #include "mozilla/gfx/ssse3-scaler.h" #include "mozilla/layers/ImageDataSerializer.h" #include "mozilla/SSE.h" +#include "mozilla/StaticPrefs.h" #include "gfxPlatform.h" #include "gfxUtils.h" #include "YCbCrUtils.h" diff --git a/gfx/layers/composite/CompositableHost.cpp b/gfx/layers/composite/CompositableHost.cpp index 8cedc7ed2c5f..5dcb98bba2aa 100644 --- a/gfx/layers/composite/CompositableHost.cpp +++ b/gfx/layers/composite/CompositableHost.cpp @@ -11,6 +11,7 @@ #include "Effects.h" // for EffectMask, Effect, etc #include "gfxUtils.h" #include "ImageHost.h" // for ImageHostBuffered, etc +#include "Layers.h" #include "TiledContentHost.h" // for TiledContentHost #include "mozilla/gfx/gfxVars.h" #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor diff --git a/gfx/layers/composite/CompositorScreenshotGrabber.cpp b/gfx/layers/composite/CompositorScreenshotGrabber.cpp index 99cc263672ff..dc3be46d733d 100644 --- a/gfx/layers/composite/CompositorScreenshotGrabber.cpp +++ b/gfx/layers/composite/CompositorScreenshotGrabber.cpp @@ -10,7 +10,9 @@ #include "mozilla/TimeStamp.h" #include "mozilla/UniquePtr.h" +#include "mozilla/layers/Compositor.h" #include "mozilla/layers/ProfilerScreenshots.h" +#include "mozilla/layers/TextureHost.h" #include "mozilla/gfx/Point.h" #include "nsTArray.h" diff --git a/gfx/layers/composite/CompositorScreenshotGrabber.h b/gfx/layers/composite/CompositorScreenshotGrabber.h index e9b4754bf526..88e2a4a6afdf 100644 --- a/gfx/layers/composite/CompositorScreenshotGrabber.h +++ b/gfx/layers/composite/CompositorScreenshotGrabber.h @@ -12,6 +12,7 @@ namespace mozilla { namespace layers { +class Compositor; class CompositorScreenshotGrabberImpl; /** diff --git a/gfx/layers/composite/TiledContentHost.cpp b/gfx/layers/composite/TiledContentHost.cpp index 5531efc4150a..b01ba6c3c8f7 100644 --- a/gfx/layers/composite/TiledContentHost.cpp +++ b/gfx/layers/composite/TiledContentHost.cpp @@ -15,6 +15,7 @@ // clang-format on #include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper +#include "mozilla/layers/PTextureParent.h" #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL #ifdef XP_DARWIN # include "mozilla/layers/TextureSync.h" // for TextureSync diff --git a/gfx/layers/d3d11/MLGDeviceD3D11.cpp b/gfx/layers/d3d11/MLGDeviceD3D11.cpp index f6cb764b64a3..a254ce016bbb 100644 --- a/gfx/layers/d3d11/MLGDeviceD3D11.cpp +++ b/gfx/layers/d3d11/MLGDeviceD3D11.cpp @@ -11,6 +11,7 @@ #include "mozilla/gfx/GPUParent.h" #include "mozilla/gfx/StackArray.h" #include "mozilla/layers/DiagnosticsD3D11.h" +#include "mozilla/layers/HelpersD3D11.h" #include "mozilla/layers/LayerMLGPU.h" #include "mozilla/layers/MemoryReportingMLGPU.h" #include "mozilla/layers/ShaderDefinitionsMLGPU.h" @@ -18,6 +19,7 @@ #include "mozilla/widget/CompositorWidget.h" #include "mozilla/widget/WinCompositorWidget.h" #include "MLGShaders.h" +#include "LayersLogging.h" #include "TextureD3D11.h" #include "gfxConfig.h" #include "mozilla/StaticPrefs.h" diff --git a/gfx/layers/d3d11/TextureD3D11.cpp b/gfx/layers/d3d11/TextureD3D11.cpp index 9ff85ff2163e..f04a12a1ac39 100644 --- a/gfx/layers/d3d11/TextureD3D11.cpp +++ b/gfx/layers/d3d11/TextureD3D11.cpp @@ -13,11 +13,13 @@ #include "gfxContext.h" #include "mozilla/StaticPrefs.h" #include "gfxWindowsPlatform.h" +#include "MainThreadUtils.h" #include "mozilla/gfx/DataSurfaceHelpers.h" #include "mozilla/gfx/DeviceManagerDx.h" #include "mozilla/gfx/Logging.h" #include "mozilla/gfx/gfxVars.h" #include "mozilla/layers/CompositorBridgeChild.h" +#include "mozilla/Telemetry.h" #include "mozilla/webrender/RenderD3D11TextureHostOGL.h" #include "mozilla/webrender/RenderThread.h" #include "mozilla/webrender/WebRenderAPI.h" diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index 0fa00d60b91e..7c38d72431d7 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -1871,7 +1871,7 @@ Maybe CompositorBridgeParent::GetTestingTimeStamp() const { return mTestTime; } -static void EraseLayerState(LayersId aId) { +void EraseLayerState(LayersId aId) { RefPtr apz; { // scope lock @@ -2189,8 +2189,8 @@ void CompositorBridgeParent::InvalidateRemoteLayers() { }); } -static void UpdateIndirectTree(LayersId aId, Layer* aRoot, - const TargetConfig& aTargetConfig) { +void UpdateIndirectTree(LayersId aId, Layer* aRoot, + const TargetConfig& aTargetConfig) { MonitorAutoLock lock(*sIndirectLayerTreesLock); sIndirectLayerTrees[aId].mRoot = aRoot; sIndirectLayerTrees[aId].mTargetConfig = aTargetConfig; diff --git a/gfx/layers/ipc/ContentCompositorBridgeParent.cpp b/gfx/layers/ipc/ContentCompositorBridgeParent.cpp index 18dcfd6feef7..1a097250c4c1 100644 --- a/gfx/layers/ipc/ContentCompositorBridgeParent.cpp +++ b/gfx/layers/ipc/ContentCompositorBridgeParent.cpp @@ -13,6 +13,7 @@ #include "base/message_loop.h" // for MessageLoop #include "base/task.h" // for CancelableTask, etc #include "base/thread.h" // for Thread +#include "gfxUtils.h" #ifdef XP_WIN # include "mozilla/gfx/DeviceManagerDx.h" // for DeviceManagerDx #endif @@ -35,7 +36,10 @@ #include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop #include "mozilla/Unused.h" #include "mozilla/StaticPtr.h" -#include "gfxUtils.h" +#include "mozilla/Telemetry.h" +#ifdef MOZ_GECKO_PROFILER +# include "ProfilerMarkerPayload.h" +#endif using namespace std; @@ -306,12 +310,12 @@ mozilla::ipc::IPCResult ContentCompositorBridgeParent::RecvCheckContentOnlyTDR( const uint32_t& sequenceNum, bool* isContentOnlyTDR) { *isContentOnlyTDR = false; #ifdef XP_WIN - ContentDeviceData compositor; + gfx::ContentDeviceData compositor; - DeviceManagerDx* dm = DeviceManagerDx::Get(); + gfx::DeviceManagerDx* dm = gfx::DeviceManagerDx::Get(); // Check that the D3D11 device sequence numbers match. - D3D11DeviceStatus status; + gfx::D3D11DeviceStatus status; dm->ExportDeviceInfo(&status); if (sequenceNum == status.sequenceNumber() && !dm->HasDeviceReset()) { diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp index 4bd1362f4111..199663489576 100644 --- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -20,6 +20,7 @@ #include "mozilla/ReentrantMonitor.h" // for ReentrantMonitor, etc #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc #include "mozilla/ipc/Transport.h" // for Transport +#include "mozilla/gfx/gfxVars.h" #include "mozilla/gfx/Point.h" // for IntSize #include "mozilla/layers/AsyncCanvasRenderer.h" #include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager diff --git a/gfx/layers/ipc/UiCompositorControllerParent.cpp b/gfx/layers/ipc/UiCompositorControllerParent.cpp index f55607240893..0fff6d9206df 100644 --- a/gfx/layers/ipc/UiCompositorControllerParent.cpp +++ b/gfx/layers/ipc/UiCompositorControllerParent.cpp @@ -7,11 +7,13 @@ #if defined(MOZ_WIDGET_ANDROID) # include "apz/src/APZCTreeManager.h" +# include "mozilla/layers/AsyncCompositionManager.h" #endif #include "mozilla/layers/Compositor.h" #include "mozilla/layers/CompositorBridgeParent.h" #include "mozilla/layers/CompositorThread.h" #include "mozilla/layers/LayerManagerComposite.h" +#include "mozilla/layers/UiCompositorControllerMessageTypes.h" #include "mozilla/gfx/Types.h" #include "mozilla/Move.h" #include "mozilla/Unused.h" diff --git a/gfx/layers/wr/RenderRootStateManager.cpp b/gfx/layers/wr/RenderRootStateManager.cpp index 5f61abd3900e..d47dfcec099c 100644 --- a/gfx/layers/wr/RenderRootStateManager.cpp +++ b/gfx/layers/wr/RenderRootStateManager.cpp @@ -7,6 +7,7 @@ #include "mozilla/layers/RenderRootStateManager.h" #include "mozilla/layers/WebRenderBridgeChild.h" +#include "mozilla/layers/WebRenderLayerManager.h" namespace mozilla { namespace layers { diff --git a/gfx/layers/wr/WebRenderBridgeParent.h b/gfx/layers/wr/WebRenderBridgeParent.h index 42303b356c99..9f90730f36a0 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.h +++ b/gfx/layers/wr/WebRenderBridgeParent.h @@ -12,6 +12,7 @@ #include "CompositableHost.h" // for CompositableHost, ImageCompositeNotificationInfo #include "GLContextProvider.h" +#include "Layers.h" #include "mozilla/layers/CompositableTransactionParent.h" #include "mozilla/layers/CompositorTypes.h" #include "mozilla/layers/CompositorVsyncSchedulerOwner.h" diff --git a/gfx/layers/wr/WebRenderCommandBuilder.cpp b/gfx/layers/wr/WebRenderCommandBuilder.cpp index 38b389b8fd4d..ff4d997e3b0c 100644 --- a/gfx/layers/wr/WebRenderCommandBuilder.cpp +++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp @@ -12,6 +12,7 @@ #include "mozilla/gfx/2D.h" #include "mozilla/gfx/Logging.h" #include "mozilla/gfx/Types.h" +#include "mozilla/layers/AnimationHelper.h" #include "mozilla/layers/ClipManager.h" #include "mozilla/layers/ImageClient.h" #include "mozilla/layers/RenderRootStateManager.h" diff --git a/gfx/webrender_bindings/WebRenderAPI.h b/gfx/webrender_bindings/WebRenderAPI.h index bab3d9405fab..bc5f7f304621 100644 --- a/gfx/webrender_bindings/WebRenderAPI.h +++ b/gfx/webrender_bindings/WebRenderAPI.h @@ -18,6 +18,7 @@ #include "mozilla/layers/SyncObject.h" #include "mozilla/layers/WebRenderCompositionRecorder.h" #include "mozilla/Range.h" +#include "mozilla/TimeStamp.h" #include "mozilla/webrender/webrender_ffi.h" #include "mozilla/webrender/WebRenderTypes.h" #include "GLTypes.h" From 29ef4af73e0709b54f8aa1dec73aa737f6b1e929 Mon Sep 17 00:00:00 2001 From: Bob Owen Date: Sun, 2 Dec 2018 14:13:56 +0000 Subject: [PATCH 04/22] Bug 1464032 Part 2: Remove LoadEvent and replace with DoWithEvent. r=jrmuizel This patch modifies DoWithEvent so that we can more easily have a DoWithEventFromStream callable from outside of Moz2D similar to LoadEventFromStream. We will add that in a later patch for the new EventRingBuffer. It also changes the only user of LoadEventFromStream over to it, so we can can get rid of it and LoadEvent entirely. --- gfx/2d/InlineTranslator.cpp | 2 +- gfx/2d/RecordedEvent.cpp | 13 +++++-------- gfx/2d/RecordedEvent.h | 17 ++++++----------- gfx/2d/RecordedEventImpl.h | 21 +++++---------------- layout/printing/DrawEventRecorder.h | 2 +- layout/printing/PrintTranslator.cpp | 17 ++++++++++------- 6 files changed, 28 insertions(+), 44 deletions(-) diff --git a/gfx/2d/InlineTranslator.cpp b/gfx/2d/InlineTranslator.cpp index f99a1290a8aa..75d64ca03d51 100644 --- a/gfx/2d/InlineTranslator.cpp +++ b/gfx/2d/InlineTranslator.cpp @@ -69,7 +69,7 @@ bool InlineTranslator::TranslateRecording(char* aData, size_t aLen) { while (reader.good()) { bool success = RecordedEvent::DoWithEvent( reader, static_cast(eventType), - [&](RecordedEvent* recordedEvent) { + [&](RecordedEvent* recordedEvent) -> bool { // Make sure that the whole event was read from the stream // successfully. if (!reader.good()) { diff --git a/gfx/2d/RecordedEvent.cpp b/gfx/2d/RecordedEvent.cpp index 593e008d7262..aff2aeaafa12 100644 --- a/gfx/2d/RecordedEvent.cpp +++ b/gfx/2d/RecordedEvent.cpp @@ -19,14 +19,11 @@ namespace gfx { using namespace std; -RecordedEvent* RecordedEvent::LoadEventFromStream(std::istream& aStream, - EventType aType) { - return LoadEvent(aStream, aType); -} - -RecordedEvent* RecordedEvent::LoadEventFromStream(EventStream& aStream, - EventType aType) { - return LoadEvent(aStream, aType); +/* static */ +bool RecordedEvent::DoWithEventFromStream( + EventStream& aStream, EventType aType, + const std::function& aAction) { + return DoWithEvent(aStream, aType, aAction); } string RecordedEvent::GetEventName(EventType aType) { diff --git a/gfx/2d/RecordedEvent.h b/gfx/2d/RecordedEvent.h index 6b37bd1570c3..49268fc4291c 100644 --- a/gfx/2d/RecordedEvent.h +++ b/gfx/2d/RecordedEvent.h @@ -199,6 +199,7 @@ class EventStream { public: virtual void write(const char* aData, size_t aSize) = 0; virtual void read(char* aOut, size_t aSize) = 0; + virtual bool good() = 0; }; class RecordedEvent { @@ -298,17 +299,11 @@ class RecordedEvent { std::stringstream& aOutput) const; template - static RecordedEvent* LoadEvent(S& aStream, EventType aType); - static RecordedEvent* LoadEventFromStream(std::istream& aStream, - EventType aType); - static RecordedEvent* LoadEventFromStream(EventStream& aStream, - EventType aType); - - // An alternative to LoadEvent that avoids a heap allocation for the event. - // This accepts a callable `f' that will take a RecordedEvent* as a single - // parameter - template - static bool DoWithEvent(S& aStream, EventType aType, F f); + static bool DoWithEvent(S& aStream, EventType aType, + const std::function& aAction); + static bool DoWithEventFromStream( + EventStream& aStream, EventType aType, + const std::function& aAction); EventType GetType() const { return (EventType)mType; } diff --git a/gfx/2d/RecordedEventImpl.h b/gfx/2d/RecordedEventImpl.h index 09e27de02cf8..61e0e3fa001e 100644 --- a/gfx/2d/RecordedEventImpl.h +++ b/gfx/2d/RecordedEventImpl.h @@ -3486,10 +3486,6 @@ inline void RecordedFilterNodeSetInput::OutputSimpleEventInfo( aStringStream << ")"; } -#define LOAD_EVENT_TYPE(_typeenum, _class) \ - case _typeenum: \ - return new _class(aStream) - #define FOR_EACH_EVENT(f) \ f(DRAWTARGETCREATION, RecordedDrawTargetCreation); \ f(DRAWTARGETDESTRUCTION, RecordedDrawTargetDestruction); \ @@ -3537,23 +3533,16 @@ inline void RecordedFilterNodeSetInput::OutputSimpleEventInfo( f(INTOLUMINANCE, RecordedIntoLuminanceSource); \ f(EXTERNALSURFACECREATION, RecordedExternalSurfaceCreation); -template -RecordedEvent* RecordedEvent::LoadEvent(S& aStream, EventType aType) { - switch (aType) { - FOR_EACH_EVENT(LOAD_EVENT_TYPE) - default: - return nullptr; - } -} - #define DO_WITH_EVENT_TYPE(_typeenum, _class) \ case _typeenum: { \ auto e = _class(aStream); \ - return f(&e); \ + return aAction(&e); \ } -template -bool RecordedEvent::DoWithEvent(S& aStream, EventType aType, F f) { +template +bool RecordedEvent::DoWithEvent( + S& aStream, EventType aType, + const std::function& aAction) { switch (aType) { FOR_EACH_EVENT(DO_WITH_EVENT_TYPE) default: diff --git a/layout/printing/DrawEventRecorder.h b/layout/printing/DrawEventRecorder.h index 5e85871bef7d..75fb086e2a58 100644 --- a/layout/printing/DrawEventRecorder.h +++ b/layout/printing/DrawEventRecorder.h @@ -105,7 +105,7 @@ class PRFileDescStream final : public mozilla::gfx::EventStream { mGood = res >= 0 && (static_cast(res) == aSize); } - bool good() { return mGood; } + bool good() final { return mGood; } private: size_t AvailableBufferSpace() { return kBufferSize - mBufferPos; } diff --git a/layout/printing/PrintTranslator.cpp b/layout/printing/PrintTranslator.cpp index aa2b82ea39a6..079215b8d68f 100644 --- a/layout/printing/PrintTranslator.cpp +++ b/layout/printing/PrintTranslator.cpp @@ -46,15 +46,18 @@ bool PrintTranslator::TranslateRecording(PRFileDescStream& aRecording) { int32_t eventType; ReadElement(aRecording, eventType); while (aRecording.good()) { - UniquePtr recordedEvent(RecordedEvent::LoadEventFromStream( - aRecording, static_cast(eventType))); + bool success = RecordedEvent::DoWithEventFromStream( + aRecording, static_cast(eventType), + [&](RecordedEvent* recordedEvent) -> bool { + // Make sure that the whole event was read from the stream. + if (!aRecording.good()) { + return false; + } - // Make sure that the whole event was read from the stream successfully. - if (!aRecording.good() || !recordedEvent) { - return false; - } + return recordedEvent->PlayEvent(this); + }); - if (!recordedEvent->PlayEvent(this)) { + if (!success) { return false; } From b6f83f9fbb200e7e0831f64adba8958b9647a984 Mon Sep 17 00:00:00 2001 From: Bob Owen Date: Sun, 2 Dec 2018 14:14:03 +0000 Subject: [PATCH 05/22] Bug 1464032 Part 3: Remove unused GetObjectRef. r=jrmuizel --- gfx/2d/RecordedEvent.h | 2 -- gfx/2d/RecordedEventImpl.h | 31 ------------------------------- 2 files changed, 33 deletions(-) diff --git a/gfx/2d/RecordedEvent.h b/gfx/2d/RecordedEvent.h index 49268fc4291c..9b9f17c8944d 100644 --- a/gfx/2d/RecordedEvent.h +++ b/gfx/2d/RecordedEvent.h @@ -291,8 +291,6 @@ class RecordedEvent { virtual std::string GetName() const = 0; - virtual ReferencePtr GetObjectRef() const = 0; - virtual ReferencePtr GetDestinedDT() { return nullptr; } void OutputSimplePatternInfo(const PatternStorage& aStorage, diff --git a/gfx/2d/RecordedEventImpl.h b/gfx/2d/RecordedEventImpl.h index 61e0e3fa001e..5959bf09f27b 100644 --- a/gfx/2d/RecordedEventImpl.h +++ b/gfx/2d/RecordedEventImpl.h @@ -60,8 +60,6 @@ class RecordedDrawingEvent : public RecordedEventDerived { template void Record(S& aStream) const; - ReferencePtr GetObjectRef() const override; - ReferencePtr mDT; }; @@ -88,7 +86,6 @@ class RecordedDrawTargetCreation std::stringstream& aStringStream) const override; std::string GetName() const override { return "DrawTarget Creation"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } ReferencePtr mRefPtr; BackendType mBackendType; @@ -119,7 +116,6 @@ class RecordedDrawTargetDestruction void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "DrawTarget Destruction"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } ReferencePtr mRefPtr; @@ -150,7 +146,6 @@ class RecordedCreateSimilarDrawTarget std::stringstream& aStringStream) const override; std::string GetName() const override { return "CreateSimilarDrawTarget"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } ReferencePtr mRefPtr; IntSize mSize; @@ -183,7 +178,6 @@ class RecordedCreateClippedDrawTarget std::stringstream& aStringStream) const override; std::string GetName() const override { return "CreateClippedDrawTarget"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } ReferencePtr mRefPtr; IntSize mMaxSize; @@ -225,7 +219,6 @@ class RecordedCreateDrawTargetForFilter std::string GetName() const override { return "CreateSimilarDrawTargetForFilter"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } ReferencePtr mRefPtr; IntSize mMaxSize; @@ -851,7 +844,6 @@ class RecordedPathCreation : public RecordedEventDerived { void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "Path Creation"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } private: friend class RecordedEvent; @@ -877,7 +869,6 @@ class RecordedPathDestruction void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "Path Destruction"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } private: friend class RecordedEvent; @@ -911,7 +902,6 @@ class RecordedSourceSurfaceCreation void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "SourceSurface Creation"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } private: friend class RecordedEvent; @@ -940,7 +930,6 @@ class RecordedSourceSurfaceDestruction void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "SourceSurface Destruction"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } private: friend class RecordedEvent; @@ -970,7 +959,6 @@ class RecordedExternalSurfaceCreation virtual std::string GetName() const { return "SourceSurfaceSharedData Creation"; } - virtual ReferencePtr GetObjectRef() const { return mRefPtr; } private: friend class RecordedEvent; @@ -999,7 +987,6 @@ class RecordedFilterNodeCreation void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "FilterNode Creation"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } private: friend class RecordedEvent; @@ -1024,7 +1011,6 @@ class RecordedFilterNodeDestruction void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "FilterNode Destruction"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } private: friend class RecordedEvent; @@ -1056,7 +1042,6 @@ class RecordedGradientStopsCreation void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "GradientStops Creation"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } private: friend class RecordedEvent; @@ -1084,7 +1069,6 @@ class RecordedGradientStopsDestruction void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "GradientStops Destruction"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } private: friend class RecordedEvent; @@ -1107,7 +1091,6 @@ class RecordedSnapshot : public RecordedEventDerived { void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "Snapshot"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } private: friend class RecordedEvent; @@ -1137,7 +1120,6 @@ class RecordedIntoLuminanceSource void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "IntoLuminanceSource"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } private: friend class RecordedEvent; @@ -1179,7 +1161,6 @@ class RecordedFontData : public RecordedEventDerived { void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "Font Data"; } - ReferencePtr GetObjectRef() const override { return nullptr; }; void SetFontData(const uint8_t* aData, uint32_t aSize, uint32_t aIndex); @@ -1226,7 +1207,6 @@ class RecordedFontDescriptor void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "Font Desc"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } private: friend class RecordedEvent; @@ -1270,7 +1250,6 @@ class RecordedUnscaledFontCreation void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "UnscaledFont Creation"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } void SetFontInstanceData(const uint8_t* aData, uint32_t aSize); @@ -1298,7 +1277,6 @@ class RecordedUnscaledFontDestruction void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "UnscaledFont Destruction"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } private: friend class RecordedEvent; @@ -1337,7 +1315,6 @@ class RecordedScaledFontCreation void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "ScaledFont Creation"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } void SetFontInstanceData(const uint8_t* aData, uint32_t aSize, const FontVariation* aVariations, @@ -1369,7 +1346,6 @@ class RecordedScaledFontDestruction void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "ScaledFont Destruction"; } - ReferencePtr GetObjectRef() const override { return mRefPtr; } private: friend class RecordedEvent; @@ -1460,7 +1436,6 @@ class RecordedFilterNodeSetAttribute void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "SetAttribute"; } - ReferencePtr GetObjectRef() const override { return mNode; } private: friend class RecordedEvent; @@ -1500,7 +1475,6 @@ class RecordedFilterNodeSetInput void OutputSimpleEventInfo(std::stringstream& aStringStream) const override; std::string GetName() const override { return "SetInput"; } - ReferencePtr GetObjectRef() const override { return mNode; } private: friend class RecordedEvent; @@ -1741,11 +1715,6 @@ void RecordedDrawingEvent::Record(S& aStream) const { WriteElement(aStream, mDT); } -template -ReferencePtr RecordedDrawingEvent::GetObjectRef() const { - return mDT; -} - inline bool RecordedDrawTargetCreation::PlayEvent( Translator* aTranslator) const { RefPtr newDT = From 7d566c46fe3a08440b11e385fe43061cc20ef4fa Mon Sep 17 00:00:00 2001 From: Bob Owen Date: Sun, 2 Dec 2018 14:14:11 +0000 Subject: [PATCH 06/22] Bug 1464032 Part 4: Record DrawTarget::Flush and DrawTarget::DetachAllSnapshots. r=jrmuizel --- gfx/2d/DrawTargetRecording.cpp | 8 +++- gfx/2d/DrawTargetRecording.h | 6 +-- gfx/2d/RecordedEvent.h | 5 +- gfx/2d/RecordedEventImpl.h | 85 +++++++++++++++++++++++++++++++++- 4 files changed, 95 insertions(+), 9 deletions(-) diff --git a/gfx/2d/DrawTargetRecording.cpp b/gfx/2d/DrawTargetRecording.cpp index 684c5f668dab..4f0121559368 100644 --- a/gfx/2d/DrawTargetRecording.cpp +++ b/gfx/2d/DrawTargetRecording.cpp @@ -368,7 +368,13 @@ already_AddRefed DrawTargetRecording::IntoLuminanceSource( return retSurf.forget(); } -void DrawTargetRecording::DetachAllSnapshots() {} +void DrawTargetRecording::Flush() { + mRecorder->RecordEvent(RecordedFlush(this)); +} + +void DrawTargetRecording::DetachAllSnapshots() { + mRecorder->RecordEvent(RecordedDetachAllSnapshots(this)); +} void DrawTargetRecording::DrawSurface(SourceSurface* aSurface, const Rect& aDest, const Rect& aSource, diff --git a/gfx/2d/DrawTargetRecording.h b/gfx/2d/DrawTargetRecording.h index 6578925bfe10..eb2294d65d73 100644 --- a/gfx/2d/DrawTargetRecording.h +++ b/gfx/2d/DrawTargetRecording.h @@ -37,11 +37,7 @@ class DrawTargetRecording : public DrawTarget { virtual IntSize GetSize() const override { return mSize; } - /* Ensure that the DrawTarget backend has flushed all drawing operations to - * this draw target. This must be called before using the backing surface of - * this draw target outside of GFX 2D code. - */ - virtual void Flush() override { mFinalDT->Flush(); } + virtual void Flush() override; virtual void FlushItem(const IntRect& aBounds) override; diff --git a/gfx/2d/RecordedEvent.h b/gfx/2d/RecordedEvent.h index 9b9f17c8944d..7edc634f4c23 100644 --- a/gfx/2d/RecordedEvent.h +++ b/gfx/2d/RecordedEvent.h @@ -250,9 +250,10 @@ class RecordedEvent { UNSCALEDFONTDESTRUCTION, INTOLUMINANCE, EXTERNALSURFACECREATION, + FLUSH, + DETACHALLSNAPSHOTS, + LAST, }; - static const uint32_t kTotalEventTypes = - RecordedEvent::FILTERNODESETINPUT + 1; virtual ~RecordedEvent() = default; diff --git a/gfx/2d/RecordedEventImpl.h b/gfx/2d/RecordedEventImpl.h index 5959bf09f27b..50c8554d8e13 100644 --- a/gfx/2d/RecordedEventImpl.h +++ b/gfx/2d/RecordedEventImpl.h @@ -1079,6 +1079,48 @@ class RecordedGradientStopsDestruction MOZ_IMPLICIT RecordedGradientStopsDestruction(S& aStream); }; +class RecordedFlush : public RecordedDrawingEvent { + public: + explicit RecordedFlush(DrawTarget* aDT) : RecordedDrawingEvent(FLUSH, aDT) {} + + bool PlayEvent(Translator* aTranslator) const final; + + template + void Record(S& aStream) const; + virtual void OutputSimpleEventInfo( + std::stringstream& aStringStream) const override; + + virtual std::string GetName() const override { return "Flush"; } + + private: + friend class RecordedEvent; + + template + MOZ_IMPLICIT RecordedFlush(S& aStream); +}; + +class RecordedDetachAllSnapshots + : public RecordedDrawingEvent { + public: + explicit RecordedDetachAllSnapshots(DrawTarget* aDT) + : RecordedDrawingEvent(DETACHALLSNAPSHOTS, aDT) {} + + bool PlayEvent(Translator* aTranslator) const final; + + template + void Record(S& aStream) const; + virtual void OutputSimpleEventInfo( + std::stringstream& aStringStream) const override; + + virtual std::string GetName() const override { return "DetachAllSnapshots"; } + + private: + friend class RecordedEvent; + + template + MOZ_IMPLICIT RecordedDetachAllSnapshots(S& aStream); +}; + class RecordedSnapshot : public RecordedEventDerived { public: RecordedSnapshot(ReferencePtr aRefPtr, DrawTarget* aDT) @@ -3014,6 +3056,45 @@ inline void RecordedIntoLuminanceSource::OutputSimpleEventInfo( << ")"; } +inline bool RecordedFlush::PlayEvent(Translator* aTranslator) const { + aTranslator->LookupDrawTarget(mDT)->Flush(); + return true; +} + +template +void RecordedFlush::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); +} + +template +RecordedFlush::RecordedFlush(S& aStream) + : RecordedDrawingEvent(FLUSH, aStream) {} + +inline void RecordedFlush::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] Flush"; +} + +inline bool RecordedDetachAllSnapshots::PlayEvent( + Translator* aTranslator) const { + aTranslator->LookupDrawTarget(mDT)->DetachAllSnapshots(); + return true; +} + +template +void RecordedDetachAllSnapshots::Record(S& aStream) const { + RecordedDrawingEvent::Record(aStream); +} + +template +RecordedDetachAllSnapshots::RecordedDetachAllSnapshots(S& aStream) + : RecordedDrawingEvent(DETACHALLSNAPSHOTS, aStream) {} + +inline void RecordedDetachAllSnapshots::OutputSimpleEventInfo( + std::stringstream& aStringStream) const { + aStringStream << "[" << mDT << "] DetachAllSnapshots"; +} + inline bool RecordedSnapshot::PlayEvent(Translator* aTranslator) const { RefPtr src = aTranslator->LookupDrawTarget(mDT)->Snapshot(); aTranslator->AddSourceSurface(mRefPtr, src); @@ -3500,7 +3581,9 @@ inline void RecordedFilterNodeSetInput::OutputSimpleEventInfo( f(UNSCALEDFONTCREATION, RecordedUnscaledFontCreation); \ f(UNSCALEDFONTDESTRUCTION, RecordedUnscaledFontDestruction); \ f(INTOLUMINANCE, RecordedIntoLuminanceSource); \ - f(EXTERNALSURFACECREATION, RecordedExternalSurfaceCreation); + f(EXTERNALSURFACECREATION, RecordedExternalSurfaceCreation); \ + f(FLUSH, RecordedFlush); \ + f(DETACHALLSNAPSHOTS, RecordedDetachAllSnapshots); #define DO_WITH_EVENT_TYPE(_typeenum, _class) \ case _typeenum: { \ From 049e2169cc1971181b43575e2a4eddc53eac1429 Mon Sep 17 00:00:00 2001 From: Bob Owen Date: Sun, 2 Dec 2018 14:14:19 +0000 Subject: [PATCH 07/22] Bug 1464032 Part 5: Make sure the DrawTarget can create a similar DrawTarget when falling back to empty surface. r=mstange Otherwise, we crash in the content process when we try to record this. --- layout/base/nsLayoutUtils.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 54946b355ba0..0e3ec8cf0772 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -7435,7 +7435,7 @@ nsLayoutUtils::SurfaceFromOffscreenCanvas(OffscreenCanvas* aOffscreenCanvas, RefPtr& aTarget) { SurfaceFromElementResult result; - nsIntSize size = aOffscreenCanvas->GetWidthHeight(); + IntSize size = aOffscreenCanvas->GetWidthHeight(); result.mSourceSurface = aOffscreenCanvas->GetSurfaceSnapshot(&result.mAlphaType); @@ -7447,10 +7447,12 @@ nsLayoutUtils::SurfaceFromOffscreenCanvas(OffscreenCanvas* aOffscreenCanvas, RefPtr ref = aTarget ? aTarget : gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); - RefPtr dt = ref->CreateSimilarDrawTarget( - IntSize(size.width, size.height), SurfaceFormat::B8G8R8A8); - if (dt) { - result.mSourceSurface = dt->Snapshot(); + if (ref->CanCreateSimilarDrawTarget(size, SurfaceFormat::B8G8R8A8)) { + RefPtr dt = + ref->CreateSimilarDrawTarget(size, SurfaceFormat::B8G8R8A8); + if (dt) { + result.mSourceSurface = dt->Snapshot(); + } } } else if (aTarget) { RefPtr opt = @@ -7618,10 +7620,12 @@ nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement( RefPtr ref = aTarget ? aTarget : gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); - RefPtr dt = ref->CreateSimilarDrawTarget( - IntSize(size.width, size.height), SurfaceFormat::B8G8R8A8); - if (dt) { - result.mSourceSurface = dt->Snapshot(); + if (ref->CanCreateSimilarDrawTarget(size, SurfaceFormat::B8G8R8A8)) { + RefPtr dt = + ref->CreateSimilarDrawTarget(size, SurfaceFormat::B8G8R8A8); + if (dt) { + result.mSourceSurface = dt->Snapshot(); + } } } else if (aTarget) { RefPtr opt = From e25e5074c1487e49c8796d03dfea2b4c4613b367 Mon Sep 17 00:00:00 2001 From: Bob Owen Date: Wed, 28 Nov 2018 20:44:27 +0000 Subject: [PATCH 08/22] Bug 1464032 Part 6: Add remote canvas pref and refactor TextuteData creation to use it. r=mattwoodrow This is ground work for when we will be returning a recording TextureData for certain types in subsequent patches. --- dom/canvas/CanvasRenderingContext2D.cpp | 9 - gfx/config/gfxVars.h | 3 +- gfx/layers/LayersTypes.h | 10 ++ gfx/layers/PersistentBufferProvider.cpp | 16 ++ gfx/layers/client/ClientLayerManager.cpp | 3 +- gfx/layers/client/TextureClient.cpp | 213 ++++++++++++++++------- gfx/layers/client/TextureClient.h | 14 +- gfx/layers/ipc/LayersMessageUtils.h | 7 + gfx/layers/wr/WebRenderLayerManager.cpp | 13 +- gfx/thebes/gfxPlatform.cpp | 5 + modules/libpref/init/StaticPrefList.h | 7 + modules/libpref/init/all.js | 1 + 12 files changed, 221 insertions(+), 80 deletions(-) diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 60a9b2fe9401..0dc00f78f5f4 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -1407,15 +1407,6 @@ bool CanvasRenderingContext2D::TrySharedTarget( return false; } -#ifdef XP_WIN - // Bug 1285271 - Disable shared buffer provider on Windows with D2D due to - // instability - if (gfxPlatform::GetPlatform()->GetPreferredCanvasBackend() == - BackendType::DIRECT2D1_1) { - return false; - } -#endif - RefPtr layerManager = LayerManagerFromCanvasElement(mCanvasElement); diff --git a/gfx/config/gfxVars.h b/gfx/config/gfxVars.h index cc3508bbbef2..faf47966a51b 100644 --- a/gfx/config/gfxVars.h +++ b/gfx/config/gfxVars.h @@ -50,7 +50,8 @@ class gfxVarReceiver; _(UseOMTP, bool, false) \ _(AllowD3D11KeyedMutex, bool, false) \ _(SystemTextQuality, int32_t, 5 /* CLEARTYPE_QUALITY */) \ - _(LayersWindowRecordingPath, nsCString, nsCString()) + _(LayersWindowRecordingPath, nsCString, nsCString()) \ + _(RemoteCanvasEnabled, bool, false) \ /* Add new entries above this line. */ diff --git a/gfx/layers/LayersTypes.h b/gfx/layers/LayersTypes.h index 7d7f7faeb849..00a71f518f0e 100644 --- a/gfx/layers/LayersTypes.h +++ b/gfx/layers/LayersTypes.h @@ -155,6 +155,16 @@ enum class LayersBackend : int8_t { LAYERS_LAST }; +enum class TextureType : int8_t { + Unknown = 0, + D3D11, + DIB, + X11, + MacIOSurface, + AndroidNativeWindow, + Last +}; + enum class BufferMode : int8_t { BUFFER_NONE, BUFFERED }; enum class DrawRegionClip : int8_t { DRAW, NONE }; diff --git a/gfx/layers/PersistentBufferProvider.cpp b/gfx/layers/PersistentBufferProvider.cpp index df3d8fc99f4e..8222a2a37a90 100644 --- a/gfx/layers/PersistentBufferProvider.cpp +++ b/gfx/layers/PersistentBufferProvider.cpp @@ -10,6 +10,7 @@ #include "mozilla/layers/ShadowLayers.h" #include "mozilla/layers/TextureClient.h" #include "mozilla/gfx/Logging.h" +#include "mozilla/StaticPrefs.h" #include "pratom.h" #include "gfxPlatform.h" @@ -103,6 +104,21 @@ PersistentBufferProviderShared::Create(gfx::IntSize aSize, return nullptr; } + if (!StaticPrefs::PersistentBufferProviderSharedEnabled()) { + return nullptr; + } + +#ifdef XP_WIN + // Bug 1285271 - Disable shared buffer provider on Windows with D2D due to + // instability, unless we are remoting the canvas drawing to the GPU process. + if (gfxPlatform::GetPlatform()->GetPreferredCanvasBackend() == + BackendType::DIRECT2D1_1 && + !TextureData::IsRemote(aKnowsCompositor->GetCompositorBackendType(), + BackendSelector::Canvas)) { + return nullptr; + } +#endif + RefPtr texture = TextureClient::CreateForDrawing( aKnowsCompositor, aFormat, aSize, BackendSelector::Canvas, TextureFlags::DEFAULT | TextureFlags::NON_BLOCKING_READ_LOCK, diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp index 8bfae39cf9ae..2a30511be61b 100644 --- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -862,8 +862,7 @@ ClientLayerManager::CreatePersistentBufferProvider(const gfx::IntSize& aSize, // because the canvas will most likely be flattened into a thebes layer // instead of being sent to the compositor, in which case rendering into // shared memory is wasteful. - if (IsCompositingCheap() && - StaticPrefs::PersistentBufferProviderSharedEnabled()) { + if (IsCompositingCheap()) { RefPtr provider = PersistentBufferProviderShared::Create(aSize, aFormat, AsShadowForwarder()); diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index f35b3bd365f7..1164c31e73aa 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -9,6 +9,7 @@ #include "Layers.h" // for Layer, etc #include "gfx2DGlue.h" #include "gfxPlatform.h" // for gfxPlatform +#include "MainThreadUtils.h" #include "mozilla/Atomics.h" #include "mozilla/StaticPrefs.h" #include "mozilla/SystemGroup.h" @@ -235,6 +236,155 @@ class TextureChild final : PTextureChild { friend void DeallocateTextureClient(TextureDeallocParams params); }; +static inline gfx::BackendType +BackendTypeForBackendSelector(LayersBackend aLayersBackend, BackendSelector aSelector) +{ + switch (aSelector) { + case BackendSelector::Canvas: + return gfxPlatform::GetPlatform()->GetPreferredCanvasBackend(); + case BackendSelector::Content: + return gfxPlatform::GetPlatform()->GetContentBackendFor(aLayersBackend); + default: + MOZ_ASSERT_UNREACHABLE("Unknown backend selector"); + return gfx::BackendType::NONE; + } +}; + +static TextureType +GetTextureType(gfx::SurfaceFormat aFormat, gfx::IntSize aSize, + LayersBackend aLayersBackend, gfx::BackendType aBackendType, + int32_t aMaxTextureSize, TextureAllocationFlags aAllocFlags) +{ +#ifdef XP_WIN + if ((aLayersBackend == LayersBackend::LAYERS_D3D11 || + aLayersBackend == LayersBackend::LAYERS_WR) && + (aBackendType == gfx::BackendType::DIRECT2D || + aBackendType == gfx::BackendType::DIRECT2D1_1 || + (!!(aAllocFlags & ALLOC_FOR_OUT_OF_BAND_CONTENT) && + DeviceManagerDx::Get()->GetContentDevice())) && + aSize.width <= aMaxTextureSize && + aSize.height <= aMaxTextureSize && + !(aAllocFlags & ALLOC_UPDATE_FROM_SURFACE)) { + return TextureType::D3D11; + } + + if (aLayersBackend != LayersBackend::LAYERS_WR && + aFormat == SurfaceFormat::B8G8R8X8 && + aBackendType == gfx::BackendType::CAIRO && + NS_IsMainThread()) { + return TextureType::DIB; + } +#endif + +#ifdef MOZ_X11 + gfxSurfaceType type = + gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType(); + + if (aLayersBackend == LayersBackend::LAYERS_BASIC && + aBackendType == gfx::BackendType::CAIRO && + type == gfxSurfaceType::Xlib) { + return TextureType::X11; + } + if (aLayersBackend == LayersBackend::LAYERS_OPENGL && + type == gfxSurfaceType::Xlib && + aFormat != SurfaceFormat::A8 && + gl::sGLXLibrary.UseTextureFromPixmap()) { + return TextureType::X11; + } +#endif + +#ifdef XP_MACOSX + if (StaticPrefs::UseIOSurfaceTextures()) { + return TextureType::MacIOSurface; + } +#endif + +#ifdef MOZ_WIDGET_ANDROID + if (StaticPrefs::UseSurfaceTextureTextures()) { + return TextureType::AndroidNativeWindow; + } +#endif + + return TextureType::Unknown; +} + +static bool +ShouldRemoteTextureType(TextureType aTextureType, BackendSelector aSelector) +{ + if (!XRE_IsContentProcess()) { + return false; + } + + if (aSelector != BackendSelector::Canvas || !gfxVars::RemoteCanvasEnabled()) { + return false; + } + + switch (aTextureType) { + case TextureType::D3D11: + return true; + default: + return false; + } +} + +/* static */ +TextureData* +TextureData::Create(TextureForwarder* aAllocator, gfx::SurfaceFormat aFormat, + gfx::IntSize aSize, LayersBackend aLayersBackend, + int32_t aMaxTextureSize, BackendSelector aSelector, + TextureFlags aTextureFlags, + TextureAllocationFlags aAllocFlags) +{ + gfx::BackendType moz2DBackend = + BackendTypeForBackendSelector(aLayersBackend, aSelector); + + TextureType textureType = GetTextureType(aFormat, aSize, aLayersBackend, + moz2DBackend, aMaxTextureSize, + aAllocFlags); + + if (ShouldRemoteTextureType(textureType, aSelector)) { + // TODO: return a recording texture data here. + } + + switch(textureType) { +#ifdef XP_WIN + case TextureType::D3D11: + return D3D11TextureData::Create(aSize, aFormat, aAllocFlags); + case TextureType::DIB: + return DIBTextureData::Create(aSize, aFormat, aAllocator); +#endif +#ifdef MOZ_X11 + case TextureType::X11: + return X11TextureData::Create(aSize, aFormat, aTextureFlags, aAllocator); +#endif +#ifdef XP_MACOSX + case TextureType::MacIOSurface: + return MacIOSurfaceTextureData::Create(aSize, aFormat, moz2DBackend); +#endif +#ifdef MOZ_WIDGET_ANDROID + case TextureType::AndroidNativeWindow: + return AndroidNativeWindowTextureData::Create(aSize, aFormat); +#endif + default: + return nullptr; + } +} + +/* static */ +bool +TextureData::IsRemote(LayersBackend aLayersBackend, BackendSelector aSelector) +{ + gfx::BackendType moz2DBackend = + BackendTypeForBackendSelector(aLayersBackend, aSelector); + + TextureType textureType = + GetTextureType(gfx::SurfaceFormat::UNKNOWN, gfx::IntSize(1,1), + aLayersBackend, moz2DBackend, INT32_MAX, + TextureAllocationFlags::ALLOC_DEFAULT); + + return ShouldRemoteTextureType(textureType, aSelector); +} + static void DestroyTextureData(TextureData* aTextureData, LayersIPCChannel* aAllocator, bool aDeallocate, bool aMainThreadOnly) { @@ -996,19 +1146,6 @@ bool TextureClient::InitIPDLActor(KnowsCompositor* aForwarder) { PTextureChild* TextureClient::GetIPDLActor() { return mActor; } -static inline gfx::BackendType BackendTypeForBackendSelector( - LayersBackend aLayersBackend, BackendSelector aSelector) { - switch (aSelector) { - case BackendSelector::Canvas: - return gfxPlatform::GetPlatform()->GetPreferredCanvasBackend(); - case BackendSelector::Content: - return gfxPlatform::GetPlatform()->GetContentBackendFor(aLayersBackend); - default: - MOZ_ASSERT_UNREACHABLE("Unknown backend selector"); - return gfx::BackendType::NONE; - } -}; - // static already_AddRefed TextureClient::CreateForDrawing( KnowsCompositor* aAllocator, gfx::SurfaceFormat aFormat, gfx::IntSize aSize, @@ -1043,53 +1180,9 @@ already_AddRefed TextureClient::CreateForDrawing( return nullptr; } - TextureData* data = nullptr; - -#ifdef XP_WIN - if ((aLayersBackend == LayersBackend::LAYERS_D3D11 || - aLayersBackend == LayersBackend::LAYERS_WR) && - (moz2DBackend == gfx::BackendType::DIRECT2D || - moz2DBackend == gfx::BackendType::DIRECT2D1_1 || - (!!(aAllocFlags & ALLOC_FOR_OUT_OF_BAND_CONTENT) && - DeviceManagerDx::Get()->GetContentDevice())) && - aSize.width <= aMaxTextureSize && aSize.height <= aMaxTextureSize && - !(aAllocFlags & ALLOC_UPDATE_FROM_SURFACE)) { - data = D3D11TextureData::Create(aSize, aFormat, aAllocFlags); - } - - if (aLayersBackend != LayersBackend::LAYERS_WR && !data && - aFormat == SurfaceFormat::B8G8R8X8 && - moz2DBackend == gfx::BackendType::CAIRO && NS_IsMainThread()) { - data = DIBTextureData::Create(aSize, aFormat, aAllocator); - } -#endif - -#ifdef MOZ_X11 - gfxSurfaceType type = - gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType(); - - if (!data && aLayersBackend == LayersBackend::LAYERS_BASIC && - moz2DBackend == gfx::BackendType::CAIRO && type == gfxSurfaceType::Xlib) { - data = X11TextureData::Create(aSize, aFormat, aTextureFlags, aAllocator); - } - if (!data && aLayersBackend == LayersBackend::LAYERS_OPENGL && - type == gfxSurfaceType::Xlib && aFormat != SurfaceFormat::A8 && - gl::sGLXLibrary.UseTextureFromPixmap()) { - data = X11TextureData::Create(aSize, aFormat, aTextureFlags, aAllocator); - } -#endif - -#ifdef XP_MACOSX - if (!data && StaticPrefs::UseIOSurfaceTextures()) { - data = MacIOSurfaceTextureData::Create(aSize, aFormat, moz2DBackend); - } -#endif - -#ifdef MOZ_WIDGET_ANDROID - if (!data && StaticPrefs::UseSurfaceTextureTextures()) { - data = AndroidNativeWindowTextureData::Create(aSize, aFormat); - } -#endif + TextureData* data = + TextureData::Create(aAllocator, aFormat, aSize, aLayersBackend, + aMaxTextureSize, aSelector, aTextureFlags, aAllocFlags); if (data) { return MakeAndAddRef(data, aTextureFlags, aAllocator); diff --git a/gfx/layers/client/TextureClient.h b/gfx/layers/client/TextureClient.h index 66e87f0b14ab..d1f1f6ac0f91 100644 --- a/gfx/layers/client/TextureClient.h +++ b/gfx/layers/client/TextureClient.h @@ -245,7 +245,16 @@ class TextureData { canConcurrentlyReadLock(true) {} }; - TextureData() { MOZ_COUNT_CTOR(TextureData); } + static TextureData* Create(TextureForwarder* aAllocator, + gfx::SurfaceFormat aFormat, + gfx::IntSize aSize, + LayersBackend aLayersBackend, + int32_t aMaxTextureSize, + BackendSelector aSelector, + TextureFlags aTextureFlags, + TextureAllocationFlags aAllocFlags); + + static bool IsRemote(LayersBackend aLayersBackend, BackendSelector aSelector); virtual ~TextureData() { MOZ_COUNT_DTOR(TextureData); } @@ -300,6 +309,9 @@ class TextureData { virtual BufferTextureData* AsBufferTextureData() { return nullptr; } virtual GPUVideoTextureData* AsGPUVideoTextureData() { return nullptr; } + +protected: + TextureData() { MOZ_COUNT_CTOR(TextureData); } }; /** diff --git a/gfx/layers/ipc/LayersMessageUtils.h b/gfx/layers/ipc/LayersMessageUtils.h index 54d017e78fb2..0ba8ac2165e6 100644 --- a/gfx/layers/ipc/LayersMessageUtils.h +++ b/gfx/layers/ipc/LayersMessageUtils.h @@ -82,6 +82,13 @@ struct ParamTraits mozilla::layers::LayersBackend::LAYERS_NONE, mozilla::layers::LayersBackend::LAYERS_LAST> {}; +template <> +struct ParamTraits + : public ContiguousEnumSerializer< + mozilla::layers::TextureType, + mozilla::layers::TextureType::Unknown, + mozilla::layers::TextureType::Last> {}; + template <> struct ParamTraits : public ContiguousEnumSerializerInclusive< diff --git a/gfx/layers/wr/WebRenderLayerManager.cpp b/gfx/layers/wr/WebRenderLayerManager.cpp index 24cfc06cc3cf..e1c490b7dcf0 100644 --- a/gfx/layers/wr/WebRenderLayerManager.cpp +++ b/gfx/layers/wr/WebRenderLayerManager.cpp @@ -734,14 +734,13 @@ WebRenderLayerManager::CreatePersistentBufferProvider( // initialized with WebRender to reduce memory usage. gfxPlatform::GetPlatform()->EnsureDevicesInitialized(); - if (StaticPrefs::PersistentBufferProviderSharedEnabled()) { - RefPtr provider = - PersistentBufferProviderShared::Create(aSize, aFormat, - AsKnowsCompositor()); - if (provider) { - return provider.forget(); - } + RefPtr provider = + PersistentBufferProviderShared::Create(aSize, aFormat, + AsKnowsCompositor()); + if (provider) { + return provider.forget(); } + return LayerManager::CreatePersistentBufferProvider(aSize, aFormat); } diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 847fa52017fa..7fc126c3ce4a 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -2423,6 +2423,9 @@ void gfxPlatform::InitAcceleration() { VideoDecodingFailedChangedCallback, "media.hardware-video-decoding.failed"); InitGPUProcessPrefs(); + + gfxVars::SetRemoteCanvasEnabled(StaticPrefs::CanvasRemote() && + gfxConfig::IsEnabled(Feature::GPU_PROCESS)); } } @@ -3394,6 +3397,8 @@ void gfxPlatform::NotifyGPUProcessDisabled() { NS_LITERAL_CSTRING("FEATURE_FAILURE_GPU_PROCESS_DISABLED")); gfxVars::SetUseWebRender(false); } + + gfxVars::SetRemoteCanvasEnabled(false); } void gfxPlatform::FetchAndImportContentDeviceData() { diff --git a/modules/libpref/init/StaticPrefList.h b/modules/libpref/init/StaticPrefList.h index 2e58511e47d9..3a9b72b129e0 100644 --- a/modules/libpref/init/StaticPrefList.h +++ b/modules/libpref/init/StaticPrefList.h @@ -2525,6 +2525,13 @@ VARCACHE_PREF( RelaxedAtomicInt32, 0x7fff ) +VARCACHE_PREF( + Live, + "gfx.canvas.remote", + CanvasRemote, + RelaxedAtomicBool, false +) + VARCACHE_PREF( Live, "gfx.color_management.enablev4", diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 5d8d1db5f9c7..977d1cc39775 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -839,6 +839,7 @@ pref("gfx.font_ahem_antialias_none", false); // e.g., pref("gfx.canvas.azure.backends", "direct2d,skia,cairo"); pref("gfx.canvas.azure.backends", "direct2d1.1,skia,cairo"); pref("gfx.content.azure.backends", "direct2d1.1,skia,cairo"); +pref("gfx.canvas.remote", false); #else #ifdef XP_MACOSX pref("gfx.content.azure.backends", "skia"); From 8b5ea2b1461fa78df159971189eb9137b6522a87 Mon Sep 17 00:00:00 2001 From: Bob Owen Date: Sun, 2 Dec 2018 14:14:35 +0000 Subject: [PATCH 09/22] Bug 1464032 Part 7: Take snapshot before return for TextureClients with synchronization. r=mattwoodrow This is so we don't need to lock the previous back buffer when it might also be locked by the compositor. These locks are generally for copying to the next back buffer or when getting image data from the previous back buffer. This also makes it easier to asynchronously cache the DataSourceSurface in the GPU process, when a page is using getImageData. This is done in a later patch. --- gfx/layers/PersistentBufferProvider.cpp | 60 ++++++++++++++++--------- gfx/layers/PersistentBufferProvider.h | 1 + gfx/layers/client/TextureClient.cpp | 11 +++++ gfx/layers/client/TextureClient.h | 6 +++ 4 files changed, 57 insertions(+), 21 deletions(-) diff --git a/gfx/layers/PersistentBufferProvider.cpp b/gfx/layers/PersistentBufferProvider.cpp index 8222a2a37a90..8815176463ce 100644 --- a/gfx/layers/PersistentBufferProvider.cpp +++ b/gfx/layers/PersistentBufferProvider.cpp @@ -348,18 +348,23 @@ PersistentBufferProviderShared::BorrowDrawTarget( return nullptr; } + mDrawTarget = tex->BorrowDrawTarget(); if (mBack != previousBackBuffer && !aPersistedRect.IsEmpty()) { - TextureClient* previous = GetTexture(previousBackBuffer); - if (previous && previous->Lock(OpenMode::OPEN_READ)) { - DebugOnly success = - previous->CopyToTextureClient(tex, &aPersistedRect, nullptr); - MOZ_ASSERT(success); + if (mPreviousSnapshot) { + mDrawTarget->CopySurface(mPreviousSnapshot, aPersistedRect, + gfx::IntPoint(0, 0)); + } else { + TextureClient* previous = GetTexture(previousBackBuffer); + if (previous && previous->Lock(OpenMode::OPEN_READ)) { + DebugOnly success = + previous->CopyToTextureClient(tex, &aPersistedRect, nullptr); + MOZ_ASSERT(success); - previous->Unlock(); + previous->Unlock(); + } } } - - mDrawTarget = tex->BorrowDrawTarget(); + mPreviousSnapshot = nullptr; if (mDrawTarget) { // This is simply to ensure the DrawTarget gets initialized, and will detect @@ -382,12 +387,23 @@ bool PersistentBufferProviderShared::ReturnDrawTarget( // Can't change the current front buffer while its snapshot is borrowed! MOZ_ASSERT(!mSnapshot); - mDrawTarget = nullptr; - dt = nullptr; - TextureClient* back = GetTexture(mBack); MOZ_ASSERT(back); + // If our TextureClients have internal synchronization then, if locks are + // needed for reading and writing, this can cause locking issues with the + // compositor. To prevent this we take a snapshot when the DrawTarget is + // returned, so this can be used when our own BorrowSnapshot is called and + // also for copying to the next TextureClient. Using this snapshot outside of + // the locks is safe, because the TextureClient calls DetachAllSnapshots on + // its DrawTarget when we Unlock below. + if (back->HasSynchronization()) { + mPreviousSnapshot = back->BorrowSnapshot(); + } + + mDrawTarget = nullptr; + dt = nullptr; + if (back) { back->Unlock(); mFront = mBack; @@ -411,6 +427,11 @@ already_AddRefed PersistentBufferProviderShared::BorrowSnapshot() { MOZ_ASSERT(!mDrawTarget); + if (mPreviousSnapshot) { + mSnapshot = mPreviousSnapshot; + return do_AddRef(mSnapshot); + } + auto front = GetTexture(mFront); if (!front || front->IsLocked()) { MOZ_ASSERT(false); @@ -421,17 +442,9 @@ PersistentBufferProviderShared::BorrowSnapshot() { return nullptr; } - RefPtr dt = front->BorrowDrawTarget(); + mSnapshot = front->BorrowSnapshot(); - if (!dt) { - front->Unlock(); - return nullptr; - } - - mSnapshot = dt->Snapshot(); - - RefPtr snapshot = mSnapshot; - return snapshot.forget(); + return do_AddRef(mSnapshot); } void PersistentBufferProviderShared::ReturnSnapshot( @@ -442,6 +455,10 @@ void PersistentBufferProviderShared::ReturnSnapshot( mSnapshot = nullptr; snapshot = nullptr; + if (mPreviousSnapshot) { + return; + } + auto front = GetTexture(mFront); if (front) { front->Unlock(); @@ -477,6 +494,7 @@ void PersistentBufferProviderShared::ClearCachedResources() { void PersistentBufferProviderShared::Destroy() { mSnapshot = nullptr; + mPreviousSnapshot = nullptr; mDrawTarget = nullptr; for (auto& mTexture : mTextures) { diff --git a/gfx/layers/PersistentBufferProvider.h b/gfx/layers/PersistentBufferProvider.h index 1a0b88f38ba1..ba1092ae895e 100644 --- a/gfx/layers/PersistentBufferProvider.h +++ b/gfx/layers/PersistentBufferProvider.h @@ -180,6 +180,7 @@ class PersistentBufferProviderShared : public PersistentBufferProvider, RefPtr mDrawTarget; RefPtr mSnapshot; + RefPtr mPreviousSnapshot; }; struct AutoReturnSnapshot final { diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index 1164c31e73aa..621eff051c9a 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -836,6 +836,17 @@ gfx::DrawTarget* TextureClient::BorrowDrawTarget() { return mBorrowedDrawTarget; } +already_AddRefed TextureClient::BorrowSnapshot() { + MOZ_ASSERT(mIsLocked); + + RefPtr surface = mData->BorrowSnapshot(); + if (!surface) { + surface = BorrowDrawTarget()->Snapshot(); + } + + return surface.forget(); +} + bool TextureClient::BorrowMappedData(MappedTextureData& aMap) { MOZ_ASSERT(IsValid()); diff --git a/gfx/layers/client/TextureClient.h b/gfx/layers/client/TextureClient.h index d1f1f6ac0f91..d27960b8564e 100644 --- a/gfx/layers/client/TextureClient.h +++ b/gfx/layers/client/TextureClient.h @@ -268,6 +268,10 @@ class TextureData { return nullptr; } + virtual already_AddRefed BorrowSnapshot() { + return nullptr; + } + virtual bool BorrowMappedData(MappedTextureData&) { return false; } virtual bool BorrowMappedYCbCrData(MappedYCbCrTextureData&) { return false; } @@ -442,6 +446,8 @@ class TextureClient : public AtomicRefCountedWithFinalize { */ gfx::DrawTarget* BorrowDrawTarget(); + already_AddRefed BorrowSnapshot(); + /** * Similar to BorrowDrawTarget but provides direct access to the texture's * bits instead of a DrawTarget. From 8f860de188c697becfdec786471f2ca1b23c2750 Mon Sep 17 00:00:00 2001 From: Bob Owen Date: Sun, 2 Dec 2018 14:14:43 +0000 Subject: [PATCH 10/22] Bug 1464032 Part 8: Add a CanvasEventRingBuffer and CanvasDrawEventRecorder. r=Gankro These are to be used as part of recording canvas drawing in the content processes and playing it back in the GPU process through shared memory. --- gfx/2d/RecordedEvent.cpp | 7 + gfx/2d/RecordedEvent.h | 69 ++++ gfx/2d/RecordedEventImpl.h | 3 + gfx/layers/CanvasDrawEventRecorder.cpp | 455 +++++++++++++++++++++++++ gfx/layers/CanvasDrawEventRecorder.h | 232 +++++++++++++ 5 files changed, 766 insertions(+) create mode 100644 gfx/layers/CanvasDrawEventRecorder.cpp create mode 100644 gfx/layers/CanvasDrawEventRecorder.h diff --git a/gfx/2d/RecordedEvent.cpp b/gfx/2d/RecordedEvent.cpp index aff2aeaafa12..a4e7572d3544 100644 --- a/gfx/2d/RecordedEvent.cpp +++ b/gfx/2d/RecordedEvent.cpp @@ -26,6 +26,13 @@ bool RecordedEvent::DoWithEventFromStream( return DoWithEvent(aStream, aType, aAction); } +/* static */ +bool RecordedEvent::DoWithEventFromStream( + EventRingBuffer& aStream, EventType aType, + const std::function& aAction) { + return DoWithEvent(aStream, aType, aAction); +} + string RecordedEvent::GetEventName(EventType aType) { switch (aType) { case DRAWTARGETCREATION: diff --git a/gfx/2d/RecordedEvent.h b/gfx/2d/RecordedEvent.h index 7edc634f4c23..1210bbc963e9 100644 --- a/gfx/2d/RecordedEvent.h +++ b/gfx/2d/RecordedEvent.h @@ -169,6 +169,71 @@ struct MemWriter { char* mPtr; }; +// This is a simple interface for an EventRingBuffer, so we can use it in the +// RecordedEvent reading and writing machinery. +class EventRingBuffer { + public: + /** + * Templated RecordEvent function so that when we have enough contiguous + * space we can record into the buffer quickly using MemWriter. + * + * @param aRecordedEvent the event to record + */ + template + void RecordEvent(const RE* aRecordedEvent) { + SizeCollector size; + WriteElement(size, aRecordedEvent->GetType()); + aRecordedEvent->Record(size); + if (size.mTotalSize > mAvailable) { + WaitForAndRecalculateAvailableSpace(); + } + if (size.mTotalSize <= mAvailable) { + MemWriter writer(mBufPos); + WriteElement(writer, aRecordedEvent->GetType()); + aRecordedEvent->Record(writer); + UpdateWriteTotalsBy(size.mTotalSize); + } else { + WriteElement(*this, aRecordedEvent->GetType()); + aRecordedEvent->Record(*this); + } + } + + /** + * Simple write function required by WriteElement. + * + * @param aData the data to be written to the buffer + * @param aSize the number of chars to write + */ + virtual void write(const char* const aData, const size_t aSize) = 0; + + /** + * Simple read function required by ReadElement. + * + * @param aOut the pointer to read into + * @param aSize the number of chars to read + */ + virtual void read(char* const aOut, const size_t aSize) = 0; + + virtual bool good() const = 0; + + protected: + /** + * Wait until space is available for writing and then set mBufPos and + * mAvailable. + */ + virtual bool WaitForAndRecalculateAvailableSpace() = 0; + + /** + * Update write count, mBufPos and mAvailable. + * + * @param aCount number of bytes written + */ + virtual void UpdateWriteTotalsBy(uint32_t aCount) = 0; + + char* mBufPos = nullptr; + uint32_t mAvailable = 0; +}; + struct MemStream { char* mData; size_t mLength; @@ -274,6 +339,7 @@ class RecordedEvent { virtual void RecordToStream(std::ostream& aStream) const = 0; virtual void RecordToStream(EventStream& aStream) const = 0; + virtual void RecordToStream(EventRingBuffer& aStream) const = 0; virtual void RecordToStream(MemStream& aStream) const = 0; virtual void OutputSimpleEventInfo(std::stringstream& aStringStream) const {} @@ -303,6 +369,9 @@ class RecordedEvent { static bool DoWithEventFromStream( EventStream& aStream, EventType aType, const std::function& aAction); + static bool DoWithEventFromStream( + EventRingBuffer& aStream, EventType aType, + const std::function& aAction); EventType GetType() const { return (EventType)mType; } diff --git a/gfx/2d/RecordedEventImpl.h b/gfx/2d/RecordedEventImpl.h index 50c8554d8e13..c78cb9dba1e9 100644 --- a/gfx/2d/RecordedEventImpl.h +++ b/gfx/2d/RecordedEventImpl.h @@ -33,6 +33,9 @@ class RecordedEventDerived : public RecordedEvent { WriteElement(aStream, this->mType); static_cast(this)->Record(aStream); } + void RecordToStream(EventRingBuffer& aStream) const final { + aStream.RecordEvent(static_cast(this)); + } void RecordToStream(MemStream& aStream) const override { SizeCollector size; WriteElement(size, this->mType); diff --git a/gfx/layers/CanvasDrawEventRecorder.cpp b/gfx/layers/CanvasDrawEventRecorder.cpp new file mode 100644 index 000000000000..d2c1f24d0fac --- /dev/null +++ b/gfx/layers/CanvasDrawEventRecorder.cpp @@ -0,0 +1,455 @@ +/* -*- 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 "CanvasDrawEventRecorder.h" + +#include + +namespace mozilla { +namespace layers { + +static const int32_t kCheckpointEventType = -1; +static const uint32_t kMaxSpinCount = 200; + +// TODO: These timeouts are long because failure in the middle of writing or +// reading an event is probably going to be fatal to the GPU process. What we +// really need to know is whether the other process has died. +static const TimeDuration kWriterTimeout = TimeDuration::FromMilliseconds(1000); +static const TimeDuration kReaderTimeout = TimeDuration::FromMilliseconds(5000); + +static const uint32_t kCacheLineSize = 64; +static const uint32_t kStreamSize = 64 * 1024; +static const uint32_t kShmemSize = kStreamSize + (2 * kCacheLineSize); + +static_assert((static_cast(UINT32_MAX) + 1) % kStreamSize == 0, + "kStreamSize must be a power of two."); + +bool CanvasEventRingBuffer::InitWriter( + base::ProcessId aOtherPid, ipc::SharedMemoryBasic::Handle* aReadHandle, + CrossProcessSemaphoreHandle* aReaderSem, + CrossProcessSemaphoreHandle* aWriterSem, + const std::function& aResumeReaderCallback) { + mSharedMemory = MakeAndAddRef(); + if (NS_WARN_IF(!mSharedMemory->Create(kShmemSize)) || + NS_WARN_IF(!mSharedMemory->Map(kShmemSize))) { + return false; + } + + if (NS_WARN_IF(!mSharedMemory->ShareToProcess(aOtherPid, aReadHandle))) { + return false; + } + + mSharedMemory->CloseHandle(); + + mBuf = static_cast(mSharedMemory->memory()); + mBufPos = mBuf; + mAvailable = kStreamSize; + + static_assert(sizeof(ReadFooter) <= kCacheLineSize, + "ReadFooter must fit in kCacheLineSize."); + mRead = reinterpret_cast(mBuf + kStreamSize); + mRead->count = 0; + mRead->returnCount = 0; + mRead->state = State::Processing; + + static_assert(sizeof(WriteFooter) <= kCacheLineSize, + "WriteFooter must fit in kCacheLineSize."); + mWrite = reinterpret_cast(mBuf + kStreamSize + kCacheLineSize); + mWrite->count = 0; + mWrite->returnCount = 0; + mWrite->requiredDifference = 0; + mWrite->state = State::Processing; + + mReaderSemaphore.reset( + CrossProcessSemaphore::Create("SharedMemoryStreamParent", 0)); + *aReaderSem = mReaderSemaphore->ShareToProcess(aOtherPid); + mReaderSemaphore->CloseHandle(); + mWriterSemaphore.reset( + CrossProcessSemaphore::Create("SharedMemoryStreamChild", 0)); + *aWriterSem = mWriterSemaphore->ShareToProcess(aOtherPid); + mWriterSemaphore->CloseHandle(); + + mResumeReaderCallback = aResumeReaderCallback; + + mGood = true; + return true; +} + +bool CanvasEventRingBuffer::InitReader( + const ipc::SharedMemoryBasic::Handle& aReadHandle, + const CrossProcessSemaphoreHandle& aReaderSem, + const CrossProcessSemaphoreHandle& aWriterSem) { + mSharedMemory = MakeAndAddRef(); + if (NS_WARN_IF(!mSharedMemory->SetHandle( + aReadHandle, ipc::SharedMemory::RightsReadWrite)) || + NS_WARN_IF(!mSharedMemory->Map(kShmemSize))) { + return false; + } + + mSharedMemory->CloseHandle(); + + mBuf = static_cast(mSharedMemory->memory()); + mRead = reinterpret_cast(mBuf + kStreamSize); + mWrite = reinterpret_cast(mBuf + kStreamSize + kCacheLineSize); + mReaderSemaphore.reset(CrossProcessSemaphore::Create(aReaderSem)); + mReaderSemaphore->CloseHandle(); + mWriterSemaphore.reset(CrossProcessSemaphore::Create(aWriterSem)); + mWriterSemaphore->CloseHandle(); + mGood = true; + return true; +} + +bool CanvasEventRingBuffer::WaitForAndRecalculateAvailableSpace() { + uint32_t bufPos = mOurCount % kStreamSize; + uint32_t maxToWrite = kStreamSize - bufPos; + mAvailable = std::min(maxToWrite, WaitForBytesToWrite()); + if (!mAvailable) { + mGood = false; + mBufPos = nullptr; + return false; + } + + mBufPos = mBuf + bufPos; + return true; +} + +void CanvasEventRingBuffer::write(const char* const aData, const size_t aSize) { + const char* curDestPtr = aData; + size_t remainingToWrite = aSize; + if (remainingToWrite > mAvailable) { + if (!WaitForAndRecalculateAvailableSpace()) { + return; + } + } + + if (remainingToWrite <= mAvailable) { + memcpy(mBufPos, curDestPtr, remainingToWrite); + UpdateWriteTotalsBy(remainingToWrite); + return; + } + + do { + memcpy(mBufPos, curDestPtr, mAvailable); + IncrementWriteCountBy(mAvailable); + curDestPtr += mAvailable; + remainingToWrite -= mAvailable; + if (!WaitForAndRecalculateAvailableSpace()) { + return; + } + } while (remainingToWrite > mAvailable); + + memcpy(mBufPos, curDestPtr, remainingToWrite); + UpdateWriteTotalsBy(remainingToWrite); +} + +void CanvasEventRingBuffer::IncrementWriteCountBy(uint32_t aCount) { + mOurCount += aCount; + mWrite->count = mOurCount; + if (mRead->state != State::Processing) { + CheckAndSignalReader(); + } +} + +void CanvasEventRingBuffer::UpdateWriteTotalsBy(uint32_t aCount) { + IncrementWriteCountBy(aCount); + mBufPos += aCount; + mAvailable -= aCount; +} + +bool CanvasEventRingBuffer::WaitForAndRecalculateAvailableData() { + uint32_t bufPos = mOurCount % kStreamSize; + uint32_t maxToRead = kStreamSize - bufPos; + mAvailable = std::min(maxToRead, WaitForBytesToRead()); + if (!mAvailable) { + mGood = false; + mBufPos = nullptr; + return false; + } + + mBufPos = mBuf + bufPos; + return true; +} + +void CanvasEventRingBuffer::read(char* const aOut, const size_t aSize) { + char* curSrcPtr = aOut; + size_t remainingToRead = aSize; + if (remainingToRead > mAvailable) { + if (!WaitForAndRecalculateAvailableData()) { + return; + } + } + + if (remainingToRead <= mAvailable) { + memcpy(curSrcPtr, mBufPos, remainingToRead); + UpdateReadTotalsBy(remainingToRead); + return; + } + + do { + memcpy(curSrcPtr, mBufPos, mAvailable); + IncrementReadCountBy(mAvailable); + curSrcPtr += mAvailable; + remainingToRead -= mAvailable; + if (!WaitForAndRecalculateAvailableData()) { + return; + } + } while (remainingToRead > mAvailable); + + memcpy(curSrcPtr, mBufPos, remainingToRead); + UpdateReadTotalsBy(remainingToRead); +} + +void CanvasEventRingBuffer::IncrementReadCountBy(uint32_t aCount) { + mOurCount += aCount; + mRead->count = mOurCount; + if (mWrite->state != State::Processing) { + CheckAndSignalWriter(); + } +} + +void CanvasEventRingBuffer::UpdateReadTotalsBy(uint32_t aCount) { + IncrementReadCountBy(aCount); + mBufPos += aCount; + mAvailable -= aCount; +} + +void CanvasEventRingBuffer::CheckAndSignalReader() { + do { + switch (mRead->state) { + case State::Processing: + return; + case State::AboutToWait: + // The reader is making a decision about whether to wait. So, we must + // wait until it has decided to avoid races. + continue; + case State::Waiting: + if (mRead->count != mOurCount) { + // We have to use compareExchange here because the reader can change + // from Waiting to Stopped. + if (mRead->state.compareExchange(State::Waiting, State::Processing)) { + mReaderSemaphore->Signal(); + return; + } + + MOZ_ASSERT(mRead->state == State::Stopped); + continue; + } + return; + case State::Stopped: + if (mRead->count != mOurCount) { + mRead->state = State::Processing; + mResumeReaderCallback(); + } + return; + default: + MOZ_ASSERT_UNREACHABLE("Invalid waiting state."); + return; + } + } while (true); +} + +bool CanvasEventRingBuffer::HasDataToRead() { + return (mWrite->count != mOurCount); +} + +bool CanvasEventRingBuffer::StopIfEmpty() { + // Double-check that the writer isn't waiting. + CheckAndSignalWriter(); + mRead->state = State::AboutToWait; + if (HasDataToRead()) { + mRead->state = State::Processing; + return false; + } + + mRead->state = State::Stopped; + return true; +} + +bool CanvasEventRingBuffer::WaitForDataToRead(TimeDuration aTimeout) { + uint32_t spinCount = kMaxSpinCount; + do { + if (HasDataToRead()) { + return true; + } + } while (--spinCount != 0); + + // Double-check that the writer isn't waiting. + CheckAndSignalWriter(); + mRead->state = State::AboutToWait; + if (HasDataToRead()) { + mRead->state = State::Processing; + return true; + } + + mRead->state = State::Waiting; + if (!mReaderSemaphore->Wait(Some(aTimeout))) { + // We have to use compareExchange here because the writer can change our + // state if we are waiting. + if (!mRead->state.compareExchange(State::Waiting, State::Stopped)) { + MOZ_RELEASE_ASSERT(HasDataToRead()); + MOZ_RELEASE_ASSERT(mRead->state == State::Processing); + // The writer has just signaled us, so consume it before returning + MOZ_ALWAYS_TRUE(mReaderSemaphore->Wait()); + return true; + } + + return false; + } + + MOZ_RELEASE_ASSERT(HasDataToRead()); + + return true; +} + +int32_t CanvasEventRingBuffer::ReadNextEvent() { + int32_t nextEvent; + ReadElement(*this, nextEvent); + while (nextEvent == kCheckpointEventType) { + ReadElement(*this, nextEvent); + } + + return nextEvent; +} + +uint32_t CanvasEventRingBuffer::CreateCheckpoint() { + WriteElement(*this, kCheckpointEventType); + return mOurCount; +} + +bool CanvasEventRingBuffer::WaitForCheckpoint(uint32_t aCheckpoint, + TimeDuration aTimeout) { + return WaitForReadCount(aCheckpoint, aTimeout); +} + +void CanvasEventRingBuffer::CheckAndSignalWriter() { + do { + switch (mWrite->state) { + case State::Processing: + return; + case State::AboutToWait: + // The writer is making a decision about whether to wait. So, we must + // wait until it has decided to avoid races. + continue; + case State::Waiting: + if (mWrite->count - mOurCount <= mWrite->requiredDifference) { + mWrite->state = State::Processing; + mWriterSemaphore->Signal(); + } + return; + default: + MOZ_ASSERT_UNREACHABLE("Invalid waiting state."); + return; + } + } while (true); +} + +bool CanvasEventRingBuffer::WaitForReadCount(uint32_t aReadCount, + TimeDuration aTimeout) { + uint32_t requiredDifference = mOurCount - aReadCount; + uint32_t spinCount = kMaxSpinCount; + do { + if (mOurCount - mRead->count <= requiredDifference) { + return true; + } + } while (--spinCount != 0); + + // Double-check that the reader isn't waiting. + CheckAndSignalReader(); + mWrite->state = State::AboutToWait; + if (mOurCount - mRead->count <= requiredDifference) { + mWrite->state = State::Processing; + return true; + } + + mWrite->requiredDifference = requiredDifference; + mWrite->state = State::Waiting; + + uint32_t lastReadCount = mRead->count; + while (!mWriterSemaphore->Wait(Some(aTimeout))) { + if (NS_WARN_IF(mRead->count == lastReadCount)) { + return false; + } + lastReadCount = mRead->count; + } + + MOZ_ASSERT(mOurCount - mRead->count <= requiredDifference); + return true; +} + +uint32_t CanvasEventRingBuffer::WaitForBytesToWrite() { + uint32_t streamFullReadCount = mOurCount - kStreamSize; + if (!WaitForReadCount(streamFullReadCount + 1, kWriterTimeout)) { + mGood = false; + return 0; + } + + return mRead->count - streamFullReadCount; +} + +uint32_t CanvasEventRingBuffer::WaitForBytesToRead() { + if (!WaitForDataToRead(kReaderTimeout)) { + return 0; + } + + return mWrite->count - mOurCount; +} + +void CanvasEventRingBuffer::ReturnWrite(const char* aData, size_t aSize) { + uint32_t writeCount = mRead->returnCount; + uint32_t bufPos = writeCount % kStreamSize; + uint32_t bufRemaining = kStreamSize - bufPos; + uint32_t availableToWrite = + std::min(bufRemaining, (mWrite->returnCount + kStreamSize - writeCount)); + while (availableToWrite < aSize) { + if (availableToWrite) { + memcpy(mBuf + bufPos, aData, availableToWrite); + writeCount += availableToWrite; + mRead->returnCount = writeCount; + bufPos = writeCount % kStreamSize; + bufRemaining = kStreamSize - bufPos; + aData += availableToWrite; + aSize -= availableToWrite; + } + + availableToWrite = std::min( + bufRemaining, (mWrite->returnCount + kStreamSize - writeCount)); + } + + memcpy(mBuf + bufPos, aData, aSize); + writeCount += aSize; + mRead->returnCount = writeCount; +} + +void CanvasEventRingBuffer::ReturnRead(char* aOut, size_t aSize) { + uint32_t readCount = mWrite->returnCount; + uint32_t bufPos = readCount % kStreamSize; + uint32_t bufRemaining = kStreamSize - bufPos; + uint32_t availableToRead = + std::min(bufRemaining, (mRead->returnCount - readCount)); + while (availableToRead < aSize) { + if (availableToRead) { + memcpy(aOut, mBuf + bufPos, availableToRead); + readCount += availableToRead; + mWrite->returnCount = readCount; + bufPos = readCount % kStreamSize; + bufRemaining = kStreamSize - bufPos; + aOut += availableToRead; + aSize -= availableToRead; + } else { + // Double-check that the reader isn't waiting. + CheckAndSignalReader(); + } + + availableToRead = std::min(bufRemaining, (mRead->returnCount - readCount)); + } + + memcpy(aOut, mBuf + bufPos, aSize); + readCount += aSize; + mWrite->returnCount = readCount; +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/CanvasDrawEventRecorder.h b/gfx/layers/CanvasDrawEventRecorder.h new file mode 100644 index 000000000000..7603a7cc5c7a --- /dev/null +++ b/gfx/layers/CanvasDrawEventRecorder.h @@ -0,0 +1,232 @@ +/* -*- 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_layers_CanvasDrawEventRecorder_h +#define mozilla_layers_CanvasDrawEventRecorder_h + +#include "mozilla/gfx/DrawEventRecorder.h" +#include "mozilla/ipc/CrossProcessSemaphore.h" +#include "mozilla/ipc/SharedMemoryBasic.h" + +namespace mozilla { +namespace layers { + +class CanvasEventRingBuffer final : public gfx::EventRingBuffer { + public: + CanvasEventRingBuffer() {} + + /** + * Initialize the write side of a CanvasEventRingBuffer returning handles to + * the shared memory for the buffer and the two semaphores for waiting in the + * reader and the writer. + * + * @param aOtherPid process ID to share the handles to + * @param aReadHandle handle to the shared memory for the buffer + * @param aReaderSem reading blocked semaphore + * @param aWriterSem writing blocked semaphore + * @param aResumeReaderCallback callback to start the reader when it is has + * stopped + * @returns true if initialization succeeds + */ + bool InitWriter(base::ProcessId aOtherPid, + ipc::SharedMemoryBasic::Handle* aReadHandle, + CrossProcessSemaphoreHandle* aReaderSem, + CrossProcessSemaphoreHandle* aWriterSem, + const std::function& aResumeReaderCallback); + + /** + * Initialize the read side of a CanvasEventRingBuffer. + * + * @param aReadHandle handle to the shared memory for the buffer + * @param aReaderSem reading blocked semaphore + * @param aWriterSem writing blocked semaphore + * @returns true if initialization succeeds + */ + bool InitReader(const ipc::SharedMemoryBasic::Handle& aReadHandle, + const CrossProcessSemaphoreHandle& aReaderSem, + const CrossProcessSemaphoreHandle& aWriterSem); + + bool good() const final { return mGood; } + + void write(const char* const aData, const size_t aSize) final; + + bool HasDataToRead(); + + /* + * This will put the reader into a stopped state if there is no more data to + * read. If this returns false the caller is responsible for continuing + * translation at a later point. If it returns false the writer will start the + * translation again when more data is written. + * + * @returns true if stopped + */ + bool StopIfEmpty(); + + /* + * Waits for the given TimeDuration for data to become available. + * + * @returns true if data is available to read. + */ + bool WaitForDataToRead(TimeDuration aTimeout); + + int32_t ReadNextEvent(); + + void read(char* const aOut, const size_t aSize) final; + + /** + * Writes a checkpoint event to the buffer. + * + * @returns the write count after the checkpoint has been written + */ + uint32_t CreateCheckpoint(); + + /** + * Waits until the given checkpoint has been read from the buffer. + * + * @params aCheckpoint the checkpoint to wait for + * @params aTimeout duration to wait while reader is not active + * @returns true if the checkpoint was reached, false if the read count has + * not changed in the aTimeout duration. + */ + bool WaitForCheckpoint(uint32_t aCheckpoint, TimeDuration aTimeout); + + /** + * 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 + * the event that uses this. + * + * @param aData the data to be written back to the writer + * @param aSize the number of chars to write + */ + void ReturnWrite(const char* aData, size_t aSize); + + /** + * Used to read data sent back from the reader via ReturnWrite. This is done + * through the same shared memory so the writer must wait until all expected + * data is read before writing new events to the buffer. + * + * @param aOut the pointer to read into + * @param aSize the number of chars to read + */ + void ReturnRead(char* aOut, size_t aSize); + + protected: + bool WaitForAndRecalculateAvailableSpace() final; + void UpdateWriteTotalsBy(uint32_t aCount) final; + + private: + enum class State : uint32_t { + Processing, + + /** + * This is the important state to make sure the other side signals or starts + * us as soon as data or space is available. We set AboutToWait first and + * then re-check the condition. If we went straight to Waiting or Stopped + * then in between the last check and setting the state, the other side + * could have used all available data or space and never have signaled us + * because it didn't know we were about to wait, causing a deadlock. + * While we are in this state, the other side must wait until we resolve the + * AboutToWait state to one of the other states and then signal or start us + * if it needs to. + */ + AboutToWait, + Waiting, + Stopped + }; + + struct ReadFooter { + Atomic count; + Atomic returnCount; + Atomic state; + }; + + struct WriteFooter { + Atomic count; + Atomic returnCount; + Atomic requiredDifference; + Atomic state; + }; + + CanvasEventRingBuffer(const CanvasEventRingBuffer&) = delete; + void operator=(const CanvasEventRingBuffer&) = delete; + + void IncrementWriteCountBy(uint32_t aCount); + + bool WaitForReadCount(uint32_t aReadCount, TimeDuration aTimeout); + + bool WaitForAndRecalculateAvailableData(); + + void UpdateReadTotalsBy(uint32_t aCount); + void IncrementReadCountBy(uint32_t aCount); + + void CheckAndSignalReader(); + + void CheckAndSignalWriter(); + + uint32_t WaitForBytesToWrite(); + + uint32_t WaitForBytesToRead(); + + RefPtr mSharedMemory; + UniquePtr mReaderSemaphore; + UniquePtr mWriterSemaphore; + std::function mResumeReaderCallback; + char* mBuf = nullptr; + uint32_t mOurCount = 0; + WriteFooter* mWrite = nullptr; + ReadFooter* mRead = nullptr; + bool mGood = false; +}; + +class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate { + public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(CanvasDrawEventRecorder, final) + explicit CanvasDrawEventRecorder(){}; + + bool Init(base::ProcessId aOtherPid, ipc::SharedMemoryBasic::Handle* aHandle, + CrossProcessSemaphoreHandle* aReaderSem, + CrossProcessSemaphoreHandle* aWriterSem, + const std::function& aResumeReaderCallback) { + return mOutputStream.InitWriter(aOtherPid, aHandle, aReaderSem, aWriterSem, + aResumeReaderCallback); + } + + void RecordEvent(const gfx::RecordedEvent& aEvent) final { + if (!mOutputStream.good()) { + return; + } + + aEvent.RecordToStream(mOutputStream); + } + + void Flush() final {} + + void ReturnRead(char* aOut, size_t aSize) { + mOutputStream.ReturnRead(aOut, aSize); + } + + uint32_t CreateCheckpoint() { return mOutputStream.CreateCheckpoint(); } + + /** + * Waits until the given checkpoint has been read by the translator. + * + * @params aCheckpoint the checkpoint to wait for + * @params aTimeout duration to wait while translator is not actively reading + * @returns true if the checkpoint was reached, false if the translator has + * not been active in the aTimeout duration. + */ + bool WaitForCheckpoint(uint32_t aCheckpoint, TimeDuration aTimeout) { + return mOutputStream.WaitForCheckpoint(aCheckpoint, aTimeout); + } + + private: + CanvasEventRingBuffer mOutputStream; +}; + +} // namespace layers +} // namespace mozilla + +#endif // mozilla_layers_CanvasDrawEventRecorder_h From 25580a443a786ddeaf236d7616ba9352f4d8ed38 Mon Sep 17 00:00:00 2001 From: Bob Owen Date: Sun, 2 Dec 2018 14:17:02 +0000 Subject: [PATCH 11/22] Bug 1464032 Part 9: Add a D3D11 device to be used on canvas threads in the GPU process. r=jrmuizel --- gfx/ipc/GPUParent.cpp | 6 +++- gfx/thebes/DeviceManagerDx.cpp | 54 +++++++++++++++++++++++++++++++++- gfx/thebes/DeviceManagerDx.h | 4 +++ 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/gfx/ipc/GPUParent.cpp b/gfx/ipc/GPUParent.cpp index 70168205af2c..957c953b3399 100644 --- a/gfx/ipc/GPUParent.cpp +++ b/gfx/ipc/GPUParent.cpp @@ -205,7 +205,11 @@ mozilla::ipc::IPCResult GPUParent::RecvInit( #if defined(XP_WIN) if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) { - DeviceManagerDx::Get()->CreateCompositorDevices(); + if (DeviceManagerDx::Get()->CreateCompositorDevices() && + gfxVars::RemoteCanvasEnabled()) { + MOZ_ALWAYS_TRUE(DeviceManagerDx::Get()->CreateCanvasDevice()); + MOZ_ALWAYS_TRUE(Factory::EnsureDWriteFactory()); + } } if (gfxVars::UseWebRender()) { DeviceManagerDx::Get()->CreateDirectCompositionDevice(); diff --git a/gfx/thebes/DeviceManagerDx.cpp b/gfx/thebes/DeviceManagerDx.cpp index 6f7b284a7dc9..81e8944683d2 100644 --- a/gfx/thebes/DeviceManagerDx.cpp +++ b/gfx/thebes/DeviceManagerDx.cpp @@ -267,6 +267,44 @@ bool DeviceManagerDx::CreateVRDevice() { return true; } +bool DeviceManagerDx::CreateCanvasDevice() { + MOZ_ASSERT(ProcessOwnsCompositor()); + + if (mCanvasDevice) { + return true; + } + + if (!LoadD3D11()) { + return false; + } + + RefPtr adapter = GetDXGIAdapter(); + if (!adapter) { + NS_WARNING("Failed to acquire a DXGI adapter for Canvas"); + return false; + } + + UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + + HRESULT hr; + if (!CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr, + mCanvasDevice)) { + gfxCriticalError() << "Crash during D3D11 device creation for Canvas"; + return false; + } + + if (FAILED(hr) || !mCanvasDevice) { + NS_WARNING("Failed to acquire a D3D11 device for Canvas"); + return false; + } + + if (XRE_IsGPUProcess()) { + Factory::SetDirect3D11Device(mCanvasDevice); + } + + return true; +} + void DeviceManagerDx::CreateDirectCompositionDevice() { if (!gfxVars::UseWebRenderDCompWin()) { return; @@ -866,6 +904,7 @@ void DeviceManagerDx::ResetDevices() { mMLGDevice = nullptr; mCompositorDevice = nullptr; mContentDevice = nullptr; + mCanvasDevice = nullptr; mImageDevice = nullptr; mDeviceStatus = Nothing(); mDeviceResetReason = Nothing(); @@ -888,6 +927,7 @@ bool DeviceManagerDx::MaybeResetAndReacquireDevices() { bool createCompositorDevice = !!mCompositorDevice; bool createContentDevice = !!mContentDevice; + bool createCanvasDevice = !!mCanvasDevice; ResetDevices(); @@ -898,6 +938,9 @@ bool DeviceManagerDx::MaybeResetAndReacquireDevices() { if (createContentDevice) { CreateContentDevices(); } + if (createCanvasDevice) { + CreateCanvasDevice(); + } return true; } @@ -986,7 +1029,8 @@ bool DeviceManagerDx::GetAnyDeviceRemovedReason(DeviceResetReason* aOutReason) { mDeviceLock.AssertCurrentThreadOwns(); if (DidDeviceReset(mCompositorDevice, aOutReason) || - DidDeviceReset(mContentDevice, aOutReason)) { + DidDeviceReset(mContentDevice, aOutReason) || + DidDeviceReset(mCanvasDevice, aOutReason)) { return true; } @@ -1069,6 +1113,14 @@ RefPtr DeviceManagerDx::GetVRDevice() { return mVRDevice; } +RefPtr DeviceManagerDx::GetCanvasDevice() { + MutexAutoLock lock(mDeviceLock); + if (!mCanvasDevice) { + CreateCanvasDevice(); + } + return mCanvasDevice; +} + RefPtr DeviceManagerDx::GetDirectCompositionDevice() { MutexAutoLock lock(mDeviceLock); return mDirectCompositionDevice; diff --git a/gfx/thebes/DeviceManagerDx.h b/gfx/thebes/DeviceManagerDx.h index 920263387b58..d269ae15dd59 100644 --- a/gfx/thebes/DeviceManagerDx.h +++ b/gfx/thebes/DeviceManagerDx.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -56,6 +57,7 @@ class DeviceManagerDx final { RefPtr GetCompositorDevice(); RefPtr GetContentDevice(); + RefPtr GetCanvasDevice(); RefPtr GetImageDevice(); RefPtr GetDirectCompositionDevice(); RefPtr GetVRDevice(); @@ -88,6 +90,7 @@ class DeviceManagerDx final { bool CreateCompositorDevices(); void CreateContentDevices(); void CreateDirectCompositionDevice(); + bool CreateCanvasDevice(); void GetCompositorDevices( RefPtr* aOutDevice, @@ -165,6 +168,7 @@ class DeviceManagerDx final { RefPtr mAdapter; RefPtr mCompositorDevice; RefPtr mContentDevice; + RefPtr mCanvasDevice; RefPtr mImageDevice; RefPtr mVRDevice; RefPtr mDecoderDevice; From 9b1c422ff4334bd8dd20f995abd801bd52d1b621 Mon Sep 17 00:00:00 2001 From: Bob Owen Date: Sun, 2 Dec 2018 14:17:12 +0000 Subject: [PATCH 12/22] Bug 1464032 Part 10: Add a CanvasTranslator and canvas recorded events. r=jrmuizel These are extensions to the Moz2D RecordedEvents to record and play back canvas texture related functions in the GPU process. The CanvasTranslator handles the playback of these and the Moz2D ones. --- gfx/2d/InlineTranslator.h | 6 +- gfx/2d/Logging.h | 3 +- gfx/2d/RecordedEvent.h | 31 +++ gfx/2d/RecordedEventImpl.h | 29 -- gfx/layers/CanvasTranslator.cpp | 238 +++++++++++++++++ gfx/layers/CanvasTranslator.h | 216 +++++++++++++++ gfx/layers/RecordedCanvasEventImpl.h | 380 +++++++++++++++++++++++++++ 7 files changed, 870 insertions(+), 33 deletions(-) create mode 100644 gfx/layers/CanvasTranslator.cpp create mode 100644 gfx/layers/CanvasTranslator.h create mode 100644 gfx/layers/RecordedCanvasEventImpl.h diff --git a/gfx/2d/InlineTranslator.h b/gfx/2d/InlineTranslator.h index 202853f807f6..5a2656d0e7d1 100644 --- a/gfx/2d/InlineTranslator.h +++ b/gfx/2d/InlineTranslator.h @@ -126,13 +126,13 @@ class InlineTranslator : public Translator { mNativeFontResources.Put(aKey, aScaledFontResouce); } - void RemoveDrawTarget(ReferencePtr aRefPtr) final { + void RemoveDrawTarget(ReferencePtr aRefPtr) override { mDrawTargets.Remove(aRefPtr); } void RemovePath(ReferencePtr aRefPtr) final { mPaths.Remove(aRefPtr); } - void RemoveSourceSurface(ReferencePtr aRefPtr) final { + void RemoveSourceSurface(ReferencePtr aRefPtr) override { mSourceSurfaces.Remove(aRefPtr); } @@ -154,7 +154,7 @@ class InlineTranslator : public Translator { already_AddRefed CreateDrawTarget( ReferencePtr aRefPtr, const gfx::IntSize& aSize, - gfx::SurfaceFormat aFormat) final; + gfx::SurfaceFormat aFormat) override; mozilla::gfx::DrawTarget* GetReferenceDrawTarget() final { return mBaseDT; } diff --git a/gfx/2d/Logging.h b/gfx/2d/Logging.h index 600e7a67abb1..29dbe1a7f506 100644 --- a/gfx/2d/Logging.h +++ b/gfx/2d/Logging.h @@ -135,7 +135,8 @@ enum class LogReason : int { NativeFontResourceNotFound, UnscaledFontNotFound, ScaledFontNotFound, - InvalidLayerType, + InvalidLayerType, // 40 + PlayEventFailed, // End MustBeLessThanThis = 101, }; diff --git a/gfx/2d/RecordedEvent.h b/gfx/2d/RecordedEvent.h index 1210bbc963e9..4826702bbf3c 100644 --- a/gfx/2d/RecordedEvent.h +++ b/gfx/2d/RecordedEvent.h @@ -13,6 +13,8 @@ #include #include +#include "RecordingTypes.h" + namespace mozilla { namespace gfx { @@ -392,6 +394,35 @@ class RecordedEvent { std::vector mDashPatternStorage; }; +template +class RecordedEventDerived : public RecordedEvent { + using RecordedEvent::RecordedEvent; + + public: + void RecordToStream(std::ostream& aStream) const override { + WriteElement(aStream, this->mType); + static_cast(this)->Record(aStream); + } + void RecordToStream(EventStream& aStream) const override { + WriteElement(aStream, this->mType); + static_cast(this)->Record(aStream); + } + void RecordToStream(EventRingBuffer& aStream) const final { + aStream.RecordEvent(static_cast(this)); + } + void RecordToStream(MemStream& aStream) const override { + SizeCollector size; + WriteElement(size, this->mType); + static_cast(this)->Record(size); + + aStream.Resize(aStream.mLength + size.mTotalSize); + + MemWriter writer(aStream.mData + aStream.mLength - size.mTotalSize); + WriteElement(writer, this->mType); + static_cast(this)->Record(writer); + } +}; + } // namespace gfx } // namespace mozilla diff --git a/gfx/2d/RecordedEventImpl.h b/gfx/2d/RecordedEventImpl.h index c78cb9dba1e9..07d084897e36 100644 --- a/gfx/2d/RecordedEventImpl.h +++ b/gfx/2d/RecordedEventImpl.h @@ -20,35 +20,6 @@ namespace mozilla { namespace gfx { -template -class RecordedEventDerived : public RecordedEvent { - using RecordedEvent::RecordedEvent; - - public: - void RecordToStream(std::ostream& aStream) const override { - WriteElement(aStream, this->mType); - static_cast(this)->Record(aStream); - } - void RecordToStream(EventStream& aStream) const override { - WriteElement(aStream, this->mType); - static_cast(this)->Record(aStream); - } - void RecordToStream(EventRingBuffer& aStream) const final { - aStream.RecordEvent(static_cast(this)); - } - void RecordToStream(MemStream& aStream) const override { - SizeCollector size; - WriteElement(size, this->mType); - static_cast(this)->Record(size); - - aStream.Resize(aStream.mLength + size.mTotalSize); - - MemWriter writer(aStream.mData + aStream.mLength - size.mTotalSize); - WriteElement(writer, this->mType); - static_cast(this)->Record(writer); - } -}; - template class RecordedDrawingEvent : public RecordedEventDerived { public: diff --git a/gfx/layers/CanvasTranslator.cpp b/gfx/layers/CanvasTranslator.cpp new file mode 100644 index 000000000000..1bb3a6d997c4 --- /dev/null +++ b/gfx/layers/CanvasTranslator.cpp @@ -0,0 +1,238 @@ +/* -*- 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 https://mozilla.org/MPL/2.0/. */ + +#include "CanvasTranslator.h" + +#include "mozilla/gfx/Logging.h" +#include "RecordedCanvasEventImpl.h" + +#if defined(XP_WIN) +# include "mozilla/gfx/DeviceManagerDx.h" +# include "mozilla/layers/TextureD3D11.h" +#endif + +namespace mozilla { +namespace layers { + +// When in a transaction we wait for a short time because we're expecting more +// events from the content process. We don't want to wait for too long in case +// other content processes are waiting for events to process. +static const TimeDuration kReadEventTimeout = TimeDuration::FromMilliseconds(5); + +static TextureData* CreateTextureData(TextureType aTextureType, + const gfx::IntSize& aSize, + gfx::SurfaceFormat aFormat) { + TextureData* textureData = nullptr; + switch (aTextureType) { +#ifdef XP_WIN + case TextureType::D3D11: { + RefPtr device = + gfx::DeviceManagerDx::Get()->GetCanvasDevice(); + MOZ_RELEASE_ASSERT(device, "Failed to get a device for canvas drawing."); + textureData = + D3D11TextureData::Create(aSize, aFormat, ALLOC_CLEAR_BUFFER, device); + break; + } +#endif + default: + MOZ_CRASH("Unsupported TextureType for CanvasTranslator."); + } + + if (!textureData) { + MOZ_CRASH("Failed to create TextureData."); + } + + return textureData; +} + +/* static */ +UniquePtr CanvasTranslator::Create( + const TextureType& aTextureType, + const ipc::SharedMemoryBasic::Handle& aReadHandle, + const CrossProcessSemaphoreHandle& aReaderSem, + const CrossProcessSemaphoreHandle& aWriterSem) { + TextureData* textureData = CreateTextureData(aTextureType, gfx::IntSize(1, 1), + gfx::SurfaceFormat::B8G8R8A8); + textureData->Lock(OpenMode::OPEN_READ_WRITE); + RefPtr dt = textureData->BorrowDrawTarget(); + return UniquePtr(new CanvasTranslator( + aTextureType, textureData, dt, aReadHandle, aReaderSem, aWriterSem)); +} + +CanvasTranslator::CanvasTranslator( + const TextureType& aTextureType, TextureData* aTextureData, + gfx::DrawTarget* aDT, const ipc::SharedMemoryBasic::Handle& aReadHandle, + const CrossProcessSemaphoreHandle& aReaderSem, + const CrossProcessSemaphoreHandle& aWriterSem) + : gfx::InlineTranslator(aDT), + mTextureType(aTextureType), + mReferenceTextureData(aTextureData) { + mStream.InitReader(aReadHandle, aReaderSem, aWriterSem); +} + +CanvasTranslator::~CanvasTranslator() { mReferenceTextureData->Unlock(); } + +bool CanvasTranslator::TranslateRecording() { + int32_t eventType = mStream.ReadNextEvent(); + while (mStream.good()) { + bool success = RecordedEvent::DoWithEventFromStream( + mStream, static_cast(eventType), + [&](RecordedEvent* recordedEvent) -> bool { + // Make sure that the whole event was read from the stream. + if (!mStream.good()) { + return false; + } + + return recordedEvent->PlayEvent(this); + }); + + if (!success && !HandleExtensionEvent(eventType)) { + gfxDevCrash(gfx::LogReason::PlayEventFailed) + << "Failed to play canvas event type: " << eventType; + mIsValid = false; + return true; + } + + if (!mIsInTransaction) { + return mStream.StopIfEmpty(); + } + + if (!mStream.HasDataToRead()) { + // We're going to wait for the next event, so take the opportunity to + // flush the rendering. + Flush(); + if (!mStream.WaitForDataToRead(kReadEventTimeout)) { + return true; + } + } + + eventType = mStream.ReadNextEvent(); + } + + mIsValid = false; + return true; +} + +#define READ_AND_PLAY_CANVAS_EVENT_TYPE(_typeenum, _class) \ + case _typeenum: { \ + auto e = _class(mStream); \ + if (!mStream.good()) { \ + return false; \ + } \ + return e.PlayCanvasEvent(this); \ + } + +bool CanvasTranslator::HandleExtensionEvent(int32_t aType) { + // This is where we handle extensions to the Moz2D Recording events to handle + // canvas specific things. + switch (aType) { + FOR_EACH_CANVAS_EVENT(READ_AND_PLAY_CANVAS_EVENT_TYPE) + default: + return false; + } +} + +void CanvasTranslator::BeginTransaction() { mIsInTransaction = true; } + +void CanvasTranslator::Flush() { +#if defined(XP_WIN) + RefPtr device = gfx::DeviceManagerDx::Get()->GetCanvasDevice(); + RefPtr deviceContext; + device->GetImmediateContext(getter_AddRefs(deviceContext)); + deviceContext->Flush(); +#endif +} + +void CanvasTranslator::EndTransaction() { + Flush(); + mIsInTransaction = false; +} + +void CanvasTranslator::AddSurfaceDescriptor(gfx::ReferencePtr aRefPtr, + TextureData* aTextureData) { + UniquePtr descriptor = MakeUnique(); + if (!aTextureData->Serialize(*descriptor)) { + MOZ_CRASH("Failed to serialize"); + } + + MonitorAutoLock lock(mSurfaceDescriptorsMonitor); + mSurfaceDescriptors[aRefPtr] = std::move(descriptor); + mSurfaceDescriptorsMonitor.Notify(); +} + +already_AddRefed CanvasTranslator::CreateDrawTarget( + gfx::ReferencePtr aRefPtr, const gfx::IntSize& aSize, + gfx::SurfaceFormat aFormat) { + TextureData* textureData = CreateTextureData(mTextureType, aSize, aFormat); + textureData->Lock(OpenMode::OPEN_READ_WRITE); + mTextureDatas[aRefPtr] = UniquePtr(textureData); + AddSurfaceDescriptor(aRefPtr, textureData); + RefPtr dt = textureData->BorrowDrawTarget(); + AddDrawTarget(aRefPtr, dt); + + return dt.forget(); +} + +void CanvasTranslator::RemoveDrawTarget(gfx::ReferencePtr aDrawTarget) { + InlineTranslator::RemoveDrawTarget(aDrawTarget); + mTextureDatas.erase(aDrawTarget); +} + +TextureData* CanvasTranslator::LookupTextureData( + gfx::ReferencePtr aDrawTarget) { + TextureMap::const_iterator result = mTextureDatas.find(aDrawTarget); + if (result == mTextureDatas.end()) { + return nullptr; + } + return result->second.get(); +} + +UniquePtr CanvasTranslator::WaitForSurfaceDescriptor( + gfx::ReferencePtr aDrawTarget) { + MonitorAutoLock lock(mSurfaceDescriptorsMonitor); + DescriptorMap::iterator result; + while ((result = mSurfaceDescriptors.find(aDrawTarget)) == + mSurfaceDescriptors.end()) { + mSurfaceDescriptorsMonitor.Wait(); + } + + UniquePtr descriptor = std::move(result->second); + mSurfaceDescriptors.erase(aDrawTarget); + return descriptor; +} + +gfx::DataSourceSurface* CanvasTranslator::LookupDataSurface( + gfx::ReferencePtr aRefPtr) { + return mDataSurfaces.GetWeak(aRefPtr); +} + +void CanvasTranslator::AddDataSurface( + gfx::ReferencePtr aRefPtr, RefPtr&& aSurface) { + mDataSurfaces.Put(aRefPtr, aSurface); +} + +void CanvasTranslator::RemoveDataSurface(gfx::ReferencePtr aRefPtr) { + mDataSurfaces.Remove(aRefPtr); +} + +void CanvasTranslator::SetPreparedMap( + gfx::ReferencePtr aSurface, + UniquePtr aMap) { + mMappedSurface = aSurface; + mPreparedMap = std::move(aMap); +} + +UniquePtr CanvasTranslator::GetPreparedMap( + gfx::ReferencePtr aSurface) { + MOZ_RELEASE_ASSERT(mMappedSurface == aSurface, + "aSurface must match previously stored surface."); + + mMappedSurface = nullptr; + return std::move(mPreparedMap); +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/CanvasTranslator.h b/gfx/layers/CanvasTranslator.h new file mode 100644 index 000000000000..9d7f5e55cb5f --- /dev/null +++ b/gfx/layers/CanvasTranslator.h @@ -0,0 +1,216 @@ +/* -*- 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 https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_layers_CanvasTranslator_h +#define mozilla_layers_CanvasTranslator_h + +#include +#include + +#include "mozilla/gfx/InlineTranslator.h" +#include "mozilla/layers/CanvasDrawEventRecorder.h" +#include "mozilla/layers/LayersSurfaces.h" +#include "mozilla/ipc/CrossProcessSemaphore.h" +#include "mozilla/Monitor.h" +#include "mozilla/UniquePtr.h" + +namespace mozilla { +namespace layers { + +class TextureData; + +class CanvasTranslator final : public gfx::InlineTranslator { + public: + /** + * Create a canvas translator for a particular TextureType, which translates + * events from a CanvasEventRingBuffer. + * + * @param aTextureType the TextureType the translator will create + * @param aReadHandle handle to the shared memory for the + * CanvasEventRingBuffer + * @param aReaderSem reading blocked semaphore for the CanvasEventRingBuffer + * @param aWriterSem writing blocked semaphore for the CanvasEventRingBuffer + * @returns the new CanvasTranslator + */ + static UniquePtr Create( + const TextureType& aTextureType, + const ipc::SharedMemoryBasic::Handle& aReadHandle, + const CrossProcessSemaphoreHandle& aReaderSem, + const CrossProcessSemaphoreHandle& aWriterSem); + + ~CanvasTranslator(); + + bool IsValid() { return mIsValid; } + + /** + * Translates events until no more are available or the end of a transaction + * If this returns false the caller of this is responsible for re-calling + * this function. + * + * @returns true if all events are processed and false otherwise. + */ + bool TranslateRecording(); + + /** + * Marks the beginning of rendering for a transaction. While in a transaction + * the translator will wait for a short time for events before returning. + * When not in a transaction the translator will only translate one event at a + * time. + */ + void BeginTransaction(); + + /** + * Marks the end of a transaction. + */ + void EndTransaction(); + + /** + * Flushes canvas drawing, for example to a device. + */ + void Flush(); + + /** + * 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 + * the event that uses this. + * + * @param aData the data to be written back to the writer + * @param aSize the number of chars to write + */ + void ReturnWrite(const char* aData, size_t aSize) { + mStream.ReturnWrite(aData, aSize); + } + + /** + * Used during playback of events to create DrawTargets. For the + * CanvasTranslator this means creating TextureDatas and getting the + * DrawTargets from those. + * + * @param aRefPtr the key to store the created DrawTarget against + * @param aSize the size of the DrawTarget + * @param aFormat the surface format for the DrawTarget + * @returns the new DrawTarget + */ + already_AddRefed CreateDrawTarget( + gfx::ReferencePtr aRefPtr, const gfx::IntSize& aSize, + gfx::SurfaceFormat aFormat) final; + + /** + * Get the TextureData associated with a DrawTarget from another process. + * + * @param aDrawTarget the key used to find the TextureData + * @returns the TextureData found + */ + TextureData* LookupTextureData(gfx::ReferencePtr aDrawTarget); + + /** + * Waits for the SurfaceDescriptor associated with a DrawTarget from another + * process to be created and then returns it. + * + * @param aDrawTarget the key used to find the TextureData + * @returns the SurfaceDescriptor found + */ + UniquePtr WaitForSurfaceDescriptor( + gfx::ReferencePtr aDrawTarget); + + /** + * Removes the DrawTarget and other objects associated with a DrawTarget from + * another process. + * + * @param aDrawTarget the key to the objects to remove + */ + void RemoveDrawTarget(gfx::ReferencePtr aDrawTarget) final; + + /** + * Removes the SourceSurface and other objects associated with a SourceSurface + * from another process. + * + * @param aRefPtr the key to the objects to remove + */ + void RemoveSourceSurface(gfx::ReferencePtr aRefPtr) final { + RemoveDataSurface(aRefPtr); + InlineTranslator::RemoveSourceSurface(aRefPtr); + } + + /** + * Gets the cached DataSourceSurface, if it exists, associated with a + * SourceSurface from another process. + * + * @param aRefPtr the key used to find the DataSourceSurface + * @returns the DataSourceSurface or nullptr if not found + */ + gfx::DataSourceSurface* LookupDataSurface(gfx::ReferencePtr aRefPtr); + + /** + * Used to cache the DataSourceSurface from a SourceSurface associated with a + * SourceSurface from another process. This is to improve performance if we + * require the data for that SourceSurface. + * + * @param aRefPtr the key used to store the DataSourceSurface + * @param aSurface the DataSourceSurface to store + */ + void AddDataSurface(gfx::ReferencePtr aRefPtr, + RefPtr&& aSurface); + + /** + * Gets the cached DataSourceSurface, if it exists, associated with a + * SourceSurface from another process. + * + * @param aRefPtr the key used to find the DataSourceSurface + * @returns the DataSourceSurface or nullptr if not found + */ + void RemoveDataSurface(gfx::ReferencePtr aRefPtr); + + /** + * Sets a ScopedMap, to be used in a later event. + * + * @param aSurface the associated surface in the other process + * @param aMap the ScopedMap to store + */ + void SetPreparedMap(gfx::ReferencePtr aSurface, + UniquePtr aMap); + + /** + * Gets the ScopedMap stored using SetPreparedMap. + * + * @param aSurface must match the surface from the SetPreparedMap call + * @returns the ScopedMap if aSurface matches otherwise nullptr + */ + UniquePtr GetPreparedMap( + gfx::ReferencePtr aSurface); + + private: + CanvasTranslator(const TextureType& aTextureType, TextureData* aTextureData, + gfx::DrawTarget* aDrawTarget, + const ipc::SharedMemoryBasic::Handle& aReadHandle, + const CrossProcessSemaphoreHandle& aReaderSem, + const CrossProcessSemaphoreHandle& aWriterSem); + + void AddSurfaceDescriptor(gfx::ReferencePtr aRefPtr, + TextureData* atextureData); + + bool HandleExtensionEvent(int32_t aType); + + CanvasEventRingBuffer mStream; + TextureType mTextureType = TextureType::Unknown; + UniquePtr mReferenceTextureData; + typedef std::unordered_map> TextureMap; + TextureMap mTextureDatas; + nsRefPtrHashtable, gfx::DataSourceSurface> mDataSurfaces; + gfx::ReferencePtr mMappedSurface; + UniquePtr mPreparedMap; + typedef std::unordered_map> DescriptorMap; + DescriptorMap mSurfaceDescriptors; + Monitor mSurfaceDescriptorsMonitor{ + "CanvasTranslator::mSurfaceDescriptorsMonitor"}; + bool mIsValid = true; + bool mIsInTransaction = false; +}; + +} // namespace layers +} // namespace mozilla + +#endif // mozilla_layers_CanvasTranslator_h diff --git a/gfx/layers/RecordedCanvasEventImpl.h b/gfx/layers/RecordedCanvasEventImpl.h new file mode 100644 index 000000000000..7708dd83b8dc --- /dev/null +++ b/gfx/layers/RecordedCanvasEventImpl.h @@ -0,0 +1,380 @@ +/* -*- 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_layers_RecordedCanvasEventImpl_h +#define mozilla_layers_RecordedCanvasEventImpl_h + +#include "mozilla/gfx/RecordedEvent.h" +#include "mozilla/gfx/RecordingTypes.h" +#include "mozilla/layers/CanvasTranslator.h" +#include "mozilla/layers/CompositorTypes.h" +#include "mozilla/layers/TextureClient.h" + +namespace mozilla { +namespace layers { + +using gfx::DrawTarget; +using gfx::IntSize; +using gfx::RecordedEvent; +using gfx::RecordedEventDerived; +using EventType = gfx::RecordedEvent::EventType; +using gfx::ReadElement; +using gfx::ReferencePtr; +using gfx::SurfaceFormat; +using gfx::WriteElement; +using ipc::SharedMemoryBasic; + +const EventType CANVAS_BEGIN_TRANSACTION = EventType::LAST; +const EventType CANVAS_END_TRANSACTION = EventType(EventType::LAST + 1); +const EventType CANVAS_FLUSH = EventType(EventType::LAST + 2); +const EventType TEXTURE_LOCK = EventType(EventType::LAST + 3); +const EventType TEXTURE_UNLOCK = EventType(EventType::LAST + 4); +const EventType CACHE_DATA_SURFACE = EventType(EventType::LAST + 5); +const EventType PREPARE_DATA_FOR_SURFACE = EventType(EventType::LAST + 6); +const EventType GET_DATA_FOR_SURFACE = EventType(EventType::LAST + 7); + +class RecordedCanvasBeginTransaction final + : public RecordedEventDerived { + public: + RecordedCanvasBeginTransaction() + : RecordedEventDerived(CANVAS_BEGIN_TRANSACTION) {} + + template + MOZ_IMPLICIT RecordedCanvasBeginTransaction(S& aStream); + + bool PlayCanvasEvent(CanvasTranslator* aTranslator) const; + + template + void Record(S& aStream) const; + + std::string GetName() const final { return "RecordedCanvasBeginTransaction"; } +}; + +inline bool RecordedCanvasBeginTransaction::PlayCanvasEvent( + CanvasTranslator* aTranslator) const { + aTranslator->BeginTransaction(); + return true; +} + +template +void RecordedCanvasBeginTransaction::Record(S& aStream) const {} + +template +RecordedCanvasBeginTransaction::RecordedCanvasBeginTransaction(S& aStream) + : RecordedEventDerived(CANVAS_BEGIN_TRANSACTION) {} + +class RecordedCanvasEndTransaction final + : public RecordedEventDerived { + public: + RecordedCanvasEndTransaction() + : RecordedEventDerived(CANVAS_END_TRANSACTION) {} + + template + MOZ_IMPLICIT RecordedCanvasEndTransaction(S& aStream); + + bool PlayCanvasEvent(CanvasTranslator* aTranslator) const; + + template + void Record(S& aStream) const; + + std::string GetName() const final { return "RecordedCanvasEndTransaction"; } +}; + +inline bool RecordedCanvasEndTransaction::PlayCanvasEvent( + CanvasTranslator* aTranslator) const { + aTranslator->EndTransaction(); + return true; +} + +template +void RecordedCanvasEndTransaction::Record(S& aStream) const {} + +template +RecordedCanvasEndTransaction::RecordedCanvasEndTransaction(S& aStream) + : RecordedEventDerived(CANVAS_END_TRANSACTION) {} + +class RecordedCanvasFlush final + : public RecordedEventDerived { + public: + RecordedCanvasFlush() : RecordedEventDerived(CANVAS_FLUSH) {} + + template + MOZ_IMPLICIT RecordedCanvasFlush(S& aStream); + + bool PlayCanvasEvent(CanvasTranslator* aTranslator) const; + + template + void Record(S& aStream) const; + + std::string GetName() const final { return "RecordedCanvasFlush"; } +}; + +inline bool RecordedCanvasFlush::PlayCanvasEvent( + CanvasTranslator* aTranslator) const { + aTranslator->Flush(); + return true; +} + +template +void RecordedCanvasFlush::Record(S& aStream) const {} + +template +RecordedCanvasFlush::RecordedCanvasFlush(S& aStream) + : RecordedEventDerived(CANVAS_FLUSH) {} + +class RecordedTextureLock final + : public RecordedEventDerived { + public: + RecordedTextureLock(DrawTarget* aDT, const OpenMode aMode) + : RecordedEventDerived(TEXTURE_LOCK), mDT(aDT), mMode(aMode) {} + + template + MOZ_IMPLICIT RecordedTextureLock(S& aStream); + + bool PlayCanvasEvent(CanvasTranslator* aTranslator) const; + + template + void Record(S& aStream) const; + + std::string GetName() const final { return "TextureLock"; } + + private: + ReferencePtr mDT; + OpenMode mMode; +}; + +inline bool RecordedTextureLock::PlayCanvasEvent( + CanvasTranslator* aTranslator) const { + TextureData* textureData = aTranslator->LookupTextureData(mDT); + if (!textureData) { + return false; + } + + textureData->Lock(mMode); + return true; +} + +template +void RecordedTextureLock::Record(S& aStream) const { + WriteElement(aStream, mDT); + WriteElement(aStream, mMode); +} + +template +RecordedTextureLock::RecordedTextureLock(S& aStream) + : RecordedEventDerived(TEXTURE_LOCK) { + ReadElement(aStream, mDT); + ReadElement(aStream, mMode); +} + +class RecordedTextureUnlock final + : public RecordedEventDerived { + public: + explicit RecordedTextureUnlock(DrawTarget* aDT) + : RecordedEventDerived(TEXTURE_UNLOCK), mDT(aDT) {} + + template + MOZ_IMPLICIT RecordedTextureUnlock(S& aStream); + + bool PlayCanvasEvent(CanvasTranslator* aTranslator) const; + + template + void Record(S& aStream) const; + + std::string GetName() const final { return "TextureUnlock"; } + + private: + ReferencePtr mDT; +}; + +inline bool RecordedTextureUnlock::PlayCanvasEvent( + CanvasTranslator* aTranslator) const { + TextureData* textureData = aTranslator->LookupTextureData(mDT); + if (!textureData) { + return false; + } + + textureData->Unlock(); + return true; +} + +template +void RecordedTextureUnlock::Record(S& aStream) const { + WriteElement(aStream, mDT); +} + +template +RecordedTextureUnlock::RecordedTextureUnlock(S& aStream) + : RecordedEventDerived(TEXTURE_UNLOCK) { + ReadElement(aStream, mDT); +} + +class RecordedCacheDataSurface final + : public RecordedEventDerived { + public: + explicit RecordedCacheDataSurface(gfx::SourceSurface* aSurface) + : RecordedEventDerived(CACHE_DATA_SURFACE), mSurface(aSurface) {} + + template + MOZ_IMPLICIT RecordedCacheDataSurface(S& aStream); + + bool PlayCanvasEvent(CanvasTranslator* aTranslator) const; + + template + void Record(S& aStream) const; + + std::string GetName() const final { return "RecordedCacheDataSurface"; } + + private: + ReferencePtr mSurface; +}; + +inline bool RecordedCacheDataSurface::PlayCanvasEvent( + CanvasTranslator* aTranslator) const { + RefPtr surface = + aTranslator->LookupSourceSurface(mSurface); + + RefPtr dataSurface = surface->GetDataSurface(); + + aTranslator->AddDataSurface(mSurface, std::move(dataSurface)); + return true; +} + +template +void RecordedCacheDataSurface::Record(S& aStream) const { + WriteElement(aStream, mSurface); +} + +template +RecordedCacheDataSurface::RecordedCacheDataSurface(S& aStream) + : RecordedEventDerived(CACHE_DATA_SURFACE) { + ReadElement(aStream, mSurface); +} + +class RecordedPrepareDataForSurface final + : public RecordedEventDerived { + public: + explicit RecordedPrepareDataForSurface(const gfx::SourceSurface* aSurface) + : RecordedEventDerived(PREPARE_DATA_FOR_SURFACE), mSurface(aSurface) {} + + template + MOZ_IMPLICIT RecordedPrepareDataForSurface(S& aStream); + + bool PlayCanvasEvent(CanvasTranslator* aTranslator) const; + + template + void Record(S& aStream) const; + + std::string GetName() const final { return "RecordedPrepareDataForSurface"; } + + private: + ReferencePtr mSurface; +}; + +inline bool RecordedPrepareDataForSurface::PlayCanvasEvent( + CanvasTranslator* aTranslator) const { + RefPtr dataSurface = + aTranslator->LookupDataSurface(mSurface); + if (!dataSurface) { + RefPtr surface = + aTranslator->LookupSourceSurface(mSurface); + if (!surface) { + return false; + } + + dataSurface = surface->GetDataSurface(); + if (!dataSurface) { + return false; + } + } + + auto preparedMap = MakeUnique( + dataSurface, gfx::DataSourceSurface::READ); + aTranslator->SetPreparedMap(mSurface, std::move(preparedMap)); + + return true; +} + +template +void RecordedPrepareDataForSurface::Record(S& aStream) const { + WriteElement(aStream, mSurface); +} + +template +RecordedPrepareDataForSurface::RecordedPrepareDataForSurface(S& aStream) + : RecordedEventDerived(PREPARE_DATA_FOR_SURFACE) { + ReadElement(aStream, mSurface); +} + +class RecordedGetDataForSurface final + : public RecordedEventDerived { + public: + explicit RecordedGetDataForSurface(const gfx::SourceSurface* aSurface) + : RecordedEventDerived(GET_DATA_FOR_SURFACE), mSurface(aSurface) {} + + template + MOZ_IMPLICIT RecordedGetDataForSurface(S& aStream); + + bool PlayCanvasEvent(CanvasTranslator* aTranslator) const; + + template + void Record(S& aStream) const; + + std::string GetName() const final { return "RecordedGetDataForSurface"; } + + private: + ReferencePtr mSurface; +}; + +inline bool RecordedGetDataForSurface::PlayCanvasEvent( + CanvasTranslator* aTranslator) const { + RefPtr surface = + aTranslator->LookupSourceSurface(mSurface); + if (!surface) { + return false; + } + + UniquePtr map = + aTranslator->GetPreparedMap(mSurface); + + gfx::IntSize ssSize = surface->GetSize(); + size_t dataFormatWidth = ssSize.width * BytesPerPixel(surface->GetFormat()); + int32_t srcStride = map->GetStride(); + char* src = reinterpret_cast(map->GetData()); + char* endSrc = src + (ssSize.height * srcStride); + while (src < endSrc) { + aTranslator->ReturnWrite(src, dataFormatWidth); + src += srcStride; + } + + return true; +} + +template +void RecordedGetDataForSurface::Record(S& aStream) const { + WriteElement(aStream, mSurface); +} + +template +RecordedGetDataForSurface::RecordedGetDataForSurface(S& aStream) + : RecordedEventDerived(GET_DATA_FOR_SURFACE) { + ReadElement(aStream, mSurface); +} + +#define FOR_EACH_CANVAS_EVENT(f) \ + f(CANVAS_BEGIN_TRANSACTION, RecordedCanvasBeginTransaction); \ + f(CANVAS_END_TRANSACTION, RecordedCanvasEndTransaction); \ + f(CANVAS_FLUSH, RecordedCanvasFlush); \ + f(TEXTURE_LOCK, RecordedTextureLock); \ + f(TEXTURE_UNLOCK, RecordedTextureUnlock); \ + f(CACHE_DATA_SURFACE, RecordedCacheDataSurface); \ + f(PREPARE_DATA_FOR_SURFACE, RecordedPrepareDataForSurface); \ + f(GET_DATA_FOR_SURFACE, RecordedGetDataForSurface); + +} // namespace layers +} // namespace mozilla + +#endif // mozilla_layers_RecordedCanvasEventImpl_h From 2853ef80682b9b8d3964492674e0a27fd59640e1 Mon Sep 17 00:00:00 2001 From: Bob Owen Date: Sun, 2 Dec 2018 14:17:24 +0000 Subject: [PATCH 13/22] Bug 1464032 Part 11: Make SourceSurface from DrawTargetRecording::CreateSourceSurfaceFromData hold its data. r=jrmuizel This means that GetData on the returned SourceSurface will function correctly. --- gfx/2d/DrawTargetRecording.cpp | 38 +++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/gfx/2d/DrawTargetRecording.cpp b/gfx/2d/DrawTargetRecording.cpp index 4f0121559368..b2608c4d3814 100644 --- a/gfx/2d/DrawTargetRecording.cpp +++ b/gfx/2d/DrawTargetRecording.cpp @@ -85,23 +85,33 @@ class DataSourceSurfaceRecording : public DataSourceSurface { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceRecording, override) DataSourceSurfaceRecording(UniquePtr aData, IntSize aSize, - int32_t aStride, SurfaceFormat aFormat) + int32_t aStride, SurfaceFormat aFormat, + DrawEventRecorderPrivate* aRecorder) : mData(std::move(aData)), mSize(aSize), mStride(aStride), - mFormat(aFormat) {} + mFormat(aFormat), + mRecorder(aRecorder) { + mRecorder->RecordEvent(RecordedSourceSurfaceCreation( + ReferencePtr(this), mData.get(), mStride, mSize, mFormat)); + mRecorder->AddStoredObject(this); + } - ~DataSourceSurfaceRecording() {} + ~DataSourceSurfaceRecording() { + mRecorder->RemoveStoredObject(this); + mRecorder->RecordEvent( + RecordedSourceSurfaceDestruction(ReferencePtr(this))); + } - static already_AddRefed Init(uint8_t* aData, IntSize aSize, - int32_t aStride, - SurfaceFormat aFormat) { + static already_AddRefed Init( + uint8_t* aData, IntSize aSize, int32_t aStride, SurfaceFormat aFormat, + DrawEventRecorderPrivate* aRecorder) { // XXX: do we need to ensure any alignment here? auto data = MakeUnique(aStride * aSize.height); if (data) { memcpy(data.get(), aData, aStride * aSize.height); RefPtr surf = new DataSourceSurfaceRecording( - std::move(data), aSize, aStride, aFormat); + std::move(data), aSize, aStride, aFormat, aRecorder); return surf.forget(); } return nullptr; @@ -117,6 +127,7 @@ class DataSourceSurfaceRecording : public DataSourceSurface { IntSize mSize; int32_t mStride; SurfaceFormat mFormat; + RefPtr mRecorder; }; class GradientStopsRecording : public GradientStops { @@ -486,16 +497,9 @@ DrawTargetRecording::CreateSourceSurfaceFromData(unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat) const { - RefPtr surf = - DataSourceSurfaceRecording::Init(aData, aSize, aStride, aFormat); - - RefPtr retSurf = - new SourceSurfaceRecording(aSize, aFormat, mRecorder); - - mRecorder->RecordEvent( - RecordedSourceSurfaceCreation(retSurf, aData, aStride, aSize, aFormat)); - - return retSurf.forget(); + RefPtr surf = DataSourceSurfaceRecording::Init( + aData, aSize, aStride, aFormat, mRecorder); + return surf.forget(); } already_AddRefed DrawTargetRecording::OptimizeSourceSurface( From 387477fb6825d056ed5a009caffea36e231ae5a2 Mon Sep 17 00:00:00 2001 From: Bob Owen Date: Sun, 2 Dec 2018 14:19:11 +0000 Subject: [PATCH 14/22] Bug 1464032 Part 12: Add CanvasParent, CanvasChild and RecordedTextureData. r=mattwoodrow, jld RecordedTextureData records TextureData calls for play back in the GPU process. CanvasChild and CanvasParent set up the recorder and translator. They also help to manage the starting of translation and co-ordinating the translation with the frame transactions. This patch also includes other changes to wire up recording and playback. --- dom/canvas/CanvasRenderingContext2D.cpp | 63 ++++---- dom/canvas/CanvasRenderingContext2D.h | 8 +- gfx/layers/PersistentBufferProvider.cpp | 11 +- gfx/layers/client/ClientLayerManager.cpp | 2 + gfx/layers/client/TextureClient.cpp | 7 +- gfx/layers/client/TextureRecorded.cpp | 110 +++++++++++++ gfx/layers/client/TextureRecorded.h | 53 +++++++ gfx/layers/composite/TextureHost.cpp | 10 ++ gfx/layers/d3d11/TextureD3D11.cpp | 3 +- gfx/layers/ipc/CanvasChild.cpp | 150 ++++++++++++++++++ gfx/layers/ipc/CanvasChild.h | 117 ++++++++++++++ gfx/layers/ipc/CanvasParent.cpp | 125 +++++++++++++++ gfx/layers/ipc/CanvasParent.h | 97 +++++++++++ gfx/layers/ipc/CompositorBridgeChild.cpp | 27 ++++ gfx/layers/ipc/CompositorBridgeChild.h | 7 + gfx/layers/ipc/CompositorBridgeParent.cpp | 5 + gfx/layers/ipc/CompositorBridgeParent.h | 11 ++ gfx/layers/ipc/CompositorThread.cpp | 2 + .../ipc/ContentCompositorBridgeParent.cpp | 17 ++ .../ipc/ContentCompositorBridgeParent.h | 10 ++ gfx/layers/ipc/LayersSurfaces.ipdlh | 5 + gfx/layers/ipc/PCanvas.ipdl | 37 +++++ gfx/layers/ipc/PCompositorBridge.ipdl | 3 + gfx/layers/ipc/TextureForwarder.h | 6 + gfx/layers/moz.build | 11 ++ gfx/layers/wr/WebRenderLayerManager.cpp | 4 + xpcom/threads/nsThreadUtils.h | 2 + 27 files changed, 864 insertions(+), 39 deletions(-) create mode 100644 gfx/layers/client/TextureRecorded.cpp create mode 100644 gfx/layers/client/TextureRecorded.h create mode 100644 gfx/layers/ipc/CanvasChild.cpp create mode 100644 gfx/layers/ipc/CanvasChild.h create mode 100644 gfx/layers/ipc/CanvasParent.cpp create mode 100644 gfx/layers/ipc/CanvasParent.h create mode 100644 gfx/layers/ipc/PCanvas.ipdl diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 0dc00f78f5f4..404709044014 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -1611,19 +1611,13 @@ UniquePtr CanvasRenderingContext2D::GetImageBuffer( *aFormat = 0; - RefPtr snapshot; - if (mTarget) { - snapshot = mTarget->Snapshot(); - } else if (mBufferProvider) { - snapshot = mBufferProvider->BorrowSnapshot(); - } else { - EnsureTarget(); - if (!IsTargetValid()) { + if (!mBufferProvider) { + if (!EnsureTarget()) { return nullptr; } - snapshot = mTarget->Snapshot(); } + RefPtr snapshot = mBufferProvider->BorrowSnapshot(); if (snapshot) { RefPtr data = snapshot->GetDataSurface(); if (data && data->GetSize() == GetSize()) { @@ -1632,9 +1626,7 @@ UniquePtr CanvasRenderingContext2D::GetImageBuffer( } } - if (!mTarget && mBufferProvider) { - mBufferProvider->ReturnSnapshot(snapshot.forget()); - } + mBufferProvider->ReturnSnapshot(snapshot.forget()); return ret; } @@ -1672,6 +1664,29 @@ CanvasRenderingContext2D::GetInputStream(const char* aMimeType, aStream); } +already_AddRefed +CanvasRenderingContext2D::GetSurfaceSnapshot(gfxAlphaType* aOutAlphaType) { + if (!mBufferProvider) { + if (!EnsureTarget()) { + return nullptr; + } + } + + RefPtr snapshot = mBufferProvider->BorrowSnapshot(); + if (!snapshot) { + return nullptr; + } + + RefPtr dataSurface = snapshot->GetDataSurface(); + mBufferProvider->ReturnSnapshot(snapshot.forget()); + + if (aOutAlphaType) { + *aOutAlphaType = (mOpaque ? gfxAlphaType::Opaque : gfxAlphaType::Premult); + } + + return dataSurface.forget(); +} + SurfaceFormat CanvasRenderingContext2D::GetSurfaceFormat() const { return mOpaque ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8; } @@ -4920,27 +4935,21 @@ nsresult CanvasRenderingContext2D::GetImageDataArray( return NS_OK; } - RefPtr readback; - DataSourceSurface::MappedSurface rawData; - RefPtr snapshot; - if (!mTarget && mBufferProvider) { - snapshot = mBufferProvider->BorrowSnapshot(); - } else { - EnsureTarget(); - if (!IsTargetValid()) { - return NS_ERROR_FAILURE; + if (!mBufferProvider) { + if (!EnsureTarget()) { + return NS_ERROR_OUT_OF_MEMORY; } - snapshot = mTarget->Snapshot(); } - if (snapshot) { - readback = snapshot->GetDataSurface(); + RefPtr snapshot = mBufferProvider->BorrowSnapshot(); + if (!snapshot) { + return NS_ERROR_OUT_OF_MEMORY; } - if (!mTarget && mBufferProvider) { - mBufferProvider->ReturnSnapshot(snapshot.forget()); - } + RefPtr readback = snapshot->GetDataSurface(); + mBufferProvider->ReturnSnapshot(snapshot.forget()); + DataSourceSurface::MappedSurface rawData; if (!readback || !readback->Map(DataSourceSurface::READ, &rawData)) { return NS_ERROR_OUT_OF_MEMORY; } diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h index 9743e57017e2..d974c038b351 100644 --- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -409,13 +409,7 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal, nsIInputStream** aStream) override; already_AddRefed GetSurfaceSnapshot( - gfxAlphaType* aOutAlphaType = nullptr) override { - EnsureTarget(); - if (aOutAlphaType) { - *aOutAlphaType = (mOpaque ? gfxAlphaType::Opaque : gfxAlphaType::Premult); - } - return mTarget->Snapshot(); - } + gfxAlphaType* aOutAlphaType = nullptr) override; virtual void SetOpaqueValueFromOpaqueAttr(bool aOpaqueAttrValue) override; bool GetIsOpaque() override { return mOpaque; } diff --git a/gfx/layers/PersistentBufferProvider.cpp b/gfx/layers/PersistentBufferProvider.cpp index 8815176463ce..ff0f553a90c1 100644 --- a/gfx/layers/PersistentBufferProvider.cpp +++ b/gfx/layers/PersistentBufferProvider.cpp @@ -425,13 +425,18 @@ TextureClient* PersistentBufferProviderShared::GetTextureClient() { already_AddRefed PersistentBufferProviderShared::BorrowSnapshot() { - MOZ_ASSERT(!mDrawTarget); - if (mPreviousSnapshot) { mSnapshot = mPreviousSnapshot; return do_AddRef(mSnapshot); } + if (mDrawTarget) { + auto back = GetTexture(mBack); + MOZ_ASSERT(back && back->IsLocked()); + mSnapshot = back->BorrowSnapshot(); + return do_AddRef(mSnapshot); + } + auto front = GetTexture(mFront); if (!front || front->IsLocked()) { MOZ_ASSERT(false); @@ -455,7 +460,7 @@ void PersistentBufferProviderShared::ReturnSnapshot( mSnapshot = nullptr; snapshot = nullptr; - if (mPreviousSnapshot) { + if (mPreviousSnapshot || mDrawTarget) { return; } diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp index 2a30511be61b..ca07d8b7939f 100644 --- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -665,6 +665,8 @@ void ClientLayerManager::ForwardTransaction(bool aScheduleComposite) { AUTO_PROFILER_TRACING("Paint", "ForwardTransaction", GRAPHICS); TimeStamp start = TimeStamp::Now(); + GetCompositorBridgeChild()->EndCanvasTransaction(); + // Skip the synchronization for buffer since we also skip the painting during // device-reset status. With OMTP, we have to wait for async paints // before we synchronize and it's done on the paint thread. diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index 621eff051c9a..6b5fd8b6a0dc 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -20,6 +20,7 @@ #include "mozilla/layers/ImageDataSerializer.h" #include "mozilla/layers/PaintThread.h" #include "mozilla/layers/TextureClientRecycleAllocator.h" +#include "mozilla/layers/TextureRecorded.h" #include "mozilla/Mutex.h" #include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc @@ -343,7 +344,11 @@ TextureData::Create(TextureForwarder* aAllocator, gfx::SurfaceFormat aFormat, aAllocFlags); if (ShouldRemoteTextureType(textureType, aSelector)) { - // TODO: return a recording texture data here. + RefPtr canvasChild = aAllocator->GetCanvasChild(); + if (canvasChild) { + return new RecordedTextureData(canvasChild.forget(), aSize, aFormat, + textureType); + } } switch(textureType) { diff --git a/gfx/layers/client/TextureRecorded.cpp b/gfx/layers/client/TextureRecorded.cpp new file mode 100644 index 000000000000..f37e08abdb4e --- /dev/null +++ b/gfx/layers/client/TextureRecorded.cpp @@ -0,0 +1,110 @@ +/* -*- 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 "TextureRecorded.h" + +#include "RecordedCanvasEventImpl.h" + +namespace mozilla { +namespace layers { + +class SourceSurfaceCanvasRecording final : public gfx::SourceSurface { + public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceCanvasRecording, final) + + SourceSurfaceCanvasRecording(RefPtr& aRecordedSuface, + RefPtr& aCanvasChild) + : mRecordedSurface(aRecordedSuface), mCanvasChild(aCanvasChild) {} + + gfx::SurfaceType GetType() const final { return mRecordedSurface->GetType(); } + + gfx::IntSize GetSize() const final { return mRecordedSurface->GetSize(); } + + gfx::SurfaceFormat GetFormat() const final { + return mRecordedSurface->GetFormat(); + } + + already_AddRefed GetDataSurface() final { + if (!mDataSourceSurface) { + mDataSourceSurface = mCanvasChild->GetDataSurface(mRecordedSurface); + } + + return do_AddRef(mDataSourceSurface); + } + + RefPtr mRecordedSurface; + RefPtr mCanvasChild; + RefPtr mDataSourceSurface; +}; + +RecordedTextureData::RecordedTextureData( + already_AddRefed aCanvasChild, gfx::IntSize aSize, + gfx::SurfaceFormat aFormat, TextureType aTextureType) + : mCanvasChild(aCanvasChild), mSize(aSize), mFormat(aFormat) { + mCanvasChild->EnsureRecorder(aTextureType); +} + +RecordedTextureData::~RecordedTextureData() {} + +void RecordedTextureData::FillInfo(TextureData::Info& aInfo) const { + aInfo.size = mSize; + aInfo.format = mFormat; + aInfo.supportsMoz2D = true; + aInfo.hasIntermediateBuffer = false; + aInfo.hasSynchronization = true; +} + +bool RecordedTextureData::Lock(OpenMode aMode) { + mCanvasChild->EnsureBeginTransaction(); + if (!mDT) { + mDT = mCanvasChild->CreateDrawTarget(mSize, mFormat); + + // We lock the TextureData when we create it to get the remote DrawTarget. + mCanvasChild->OnTextureWriteLock(); + return true; + } + + mCanvasChild->RecordEvent(RecordedTextureLock(mDT.get(), aMode)); + if (aMode & OpenMode::OPEN_WRITE) { + mCanvasChild->OnTextureWriteLock(); + mSnapshot = nullptr; + } + return true; +} + +void RecordedTextureData::Unlock() { + mCanvasChild->RecordEvent(RecordedTextureUnlock(mDT.get())); +} + +already_AddRefed RecordedTextureData::BorrowDrawTarget() { + return do_AddRef(mDT); +} + +already_AddRefed RecordedTextureData::BorrowSnapshot() { + MOZ_ASSERT(mDT); + + mSnapshot = mDT->Snapshot(); + return MakeAndAddRef(mSnapshot, mCanvasChild); +} + +void RecordedTextureData::Deallocate(LayersIPCChannel* aAllocator) {} + +bool RecordedTextureData::Serialize(SurfaceDescriptor& aDescriptor) { + SurfaceDescriptorRecorded descriptor; + descriptor.drawTarget() = reinterpret_cast(mDT.get()); + aDescriptor = std::move(descriptor); + return true; +} + +void RecordedTextureData::OnForwardedToHost() { + mCanvasChild->OnTextureForwarded(); + if (mSnapshot && mCanvasChild->ShouldCacheDataSurface()) { + mCanvasChild->RecordEvent(RecordedCacheDataSurface(mSnapshot.get())); + } +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/client/TextureRecorded.h b/gfx/layers/client/TextureRecorded.h new file mode 100644 index 000000000000..a74b33745273 --- /dev/null +++ b/gfx/layers/client/TextureRecorded.h @@ -0,0 +1,53 @@ +/* -*- 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 https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_layers_TextureRecorded_h +#define mozilla_layers_TextureRecorded_h + +#include "TextureClient.h" +#include "mozilla/layers/CanvasChild.h" + +namespace mozilla { +namespace layers { + +class RecordedTextureData final : public TextureData { + public: + RecordedTextureData(already_AddRefed aCanvasChild, + gfx::IntSize aSize, gfx::SurfaceFormat aFormat, + TextureType aTextureType); + + void FillInfo(TextureData::Info& aInfo) const final; + + bool Lock(OpenMode aMode) final; + + void Unlock() final; + + already_AddRefed BorrowDrawTarget() final; + + already_AddRefed BorrowSnapshot() final; + + void Deallocate(LayersIPCChannel* aAllocator) final; + + bool Serialize(SurfaceDescriptor& aDescriptor) final; + + void OnForwardedToHost() final; + + private: + DISALLOW_COPY_AND_ASSIGN(RecordedTextureData); + + ~RecordedTextureData() override; + + RefPtr mCanvasChild; + gfx::IntSize mSize; + gfx::SurfaceFormat mFormat; + RefPtr mDT; + RefPtr mSnapshot; +}; + +} // namespace layers +} // namespace mozilla + +#endif // mozilla_layers_TextureRecorded_h diff --git a/gfx/layers/composite/TextureHost.cpp b/gfx/layers/composite/TextureHost.cpp index b36071d96329..2fb0a18676dd 100644 --- a/gfx/layers/composite/TextureHost.cpp +++ b/gfx/layers/composite/TextureHost.cpp @@ -216,6 +216,16 @@ already_AddRefed TextureHost::Create( result = CreateTextureHostD3D11(aDesc, aDeallocator, aBackend, aFlags); break; #endif + case SurfaceDescriptor::TSurfaceDescriptorRecorded: { + const SurfaceDescriptorRecorded& desc = + aDesc.get_SurfaceDescriptorRecorded(); + UniquePtr realDesc = + aDeallocator->AsCompositorBridgeParentBase() + ->LookupSurfaceDescriptorForClientDrawTarget(desc.drawTarget()); + result = TextureHost::Create(*realDesc, aReadLock, aDeallocator, aBackend, + aFlags, aExternalImageId); + return result.forget(); + } default: MOZ_CRASH("GFX: Unsupported Surface type host"); } diff --git a/gfx/layers/d3d11/TextureD3D11.cpp b/gfx/layers/d3d11/TextureD3D11.cpp index f04a12a1ac39..1a997e657725 100644 --- a/gfx/layers/d3d11/TextureD3D11.cpp +++ b/gfx/layers/d3d11/TextureD3D11.cpp @@ -728,7 +728,8 @@ already_AddRefed CreateTextureHostD3D11( } already_AddRefed D3D11TextureData::BorrowDrawTarget() { - MOZ_ASSERT(NS_IsMainThread() || PaintThread::IsOnPaintThread()); + MOZ_ASSERT(NS_IsMainThread() || PaintThread::IsOnPaintThread() || + NS_IsInCanvasThread()); if (!mDrawTarget && mTexture) { // This may return a null DrawTarget diff --git a/gfx/layers/ipc/CanvasChild.cpp b/gfx/layers/ipc/CanvasChild.cpp new file mode 100644 index 000000000000..955174964661 --- /dev/null +++ b/gfx/layers/ipc/CanvasChild.cpp @@ -0,0 +1,150 @@ +/* -*- 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 "CanvasChild.h" + +#include "MainThreadUtils.h" +#include "mozilla/gfx/DrawTargetRecording.h" +#include "mozilla/gfx/Tools.h" +#include "mozilla/layers/CanvasDrawEventRecorder.h" +#include "RecordedCanvasEventImpl.h" + +namespace mozilla { +namespace layers { + +static const TimeDuration kLockWaitTimeout = + TimeDuration::FromMilliseconds(100); +static const TimeDuration kGetDataTimeout = TimeDuration::FromMilliseconds(500); + +CanvasChild::CanvasChild(Endpoint&& aEndpoint) { + aEndpoint.Bind(this); + mCanSend = true; +} + +CanvasChild::~CanvasChild() {} + +void CanvasChild::EnsureRecorder(TextureType aTextureType) { + if (!mRecorder) { + MOZ_ASSERT(mTextureType == TextureType::Unknown); + mTextureType = aTextureType; + mRecorder = MakeAndAddRef(); + SharedMemoryBasic::Handle handle; + CrossProcessSemaphoreHandle readerSem; + CrossProcessSemaphoreHandle writerSem; + RefPtr thisRef = this; + mRecorder->Init(OtherPid(), &handle, &readerSem, &writerSem, + [cc = std::move(thisRef)] { cc->ResumeTranslation(); }); + + if (mCanSend) { + Unused << SendCreateTranslator(mTextureType, handle, readerSem, + writerSem); + } + } + + MOZ_RELEASE_ASSERT(mTextureType == aTextureType, + "We only support one remote TextureType currently."); +} + +void CanvasChild::ActorDestroy(ActorDestroyReason aWhy) { + mCanSend = false; + + // Explicitly drop our reference to the recorder, because it holds a reference + // to us via the ResumeTranslation callback. + mRecorder = nullptr; +} + +void CanvasChild::ResumeTranslation() { + if (mCanSend) { + SendResumeTranslation(); + } +} + +void CanvasChild::Destroy() { Close(); } + +void CanvasChild::OnTextureWriteLock() { + mHasOutstandingWriteLock = true; + mLastWriteLockCheckpoint = mRecorder->CreateCheckpoint(); +} + +void CanvasChild::OnTextureForwarded() { + if (mHasOutstandingWriteLock) { + mRecorder->RecordEvent(RecordedCanvasFlush()); + if (!mRecorder->WaitForCheckpoint(mLastWriteLockCheckpoint, + kLockWaitTimeout)) { + gfxWarning() << "Timed out waiting for last write lock to be processed."; + } + + mHasOutstandingWriteLock = false; + } +} + +void CanvasChild::EnsureBeginTransaction() { + if (!mIsInTransaction) { + mRecorder->RecordEvent(RecordedCanvasBeginTransaction()); + mIsInTransaction = true; + } +} + +void CanvasChild::EndTransaction() { + if (mIsInTransaction) { + mRecorder->RecordEvent(RecordedCanvasEndTransaction()); + mIsInTransaction = false; + } + + ++mTransactionsSinceGetDataSurface; +} + +already_AddRefed CanvasChild::CreateDrawTarget( + gfx::IntSize aSize, gfx::SurfaceFormat aFormat) { + MOZ_ASSERT(mRecorder); + + RefPtr dummyDt = gfx::Factory::CreateDrawTarget( + gfx::BackendType::SKIA, gfx::IntSize(1, 1), aFormat); + RefPtr dt = + MakeAndAddRef(mRecorder, dummyDt, aSize); + return dt.forget(); +} + +void CanvasChild::RecordEvent(const gfx::RecordedEvent& aEvent) { + mRecorder->RecordEvent(aEvent); +} + +already_AddRefed CanvasChild::GetDataSurface( + const gfx::SourceSurface* aSurface) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aSurface); + + mTransactionsSinceGetDataSurface = 0; + EnsureBeginTransaction(); + mRecorder->RecordEvent(RecordedPrepareDataForSurface(aSurface)); + uint32_t checkpoint = mRecorder->CreateCheckpoint(); + + gfx::IntSize ssSize = aSurface->GetSize(); + gfx::SurfaceFormat ssFormat = aSurface->GetFormat(); + size_t dataFormatWidth = ssSize.width * BytesPerPixel(ssFormat); + RefPtr dataSurface = + gfx::Factory::CreateDataSourceSurfaceWithStride(ssSize, ssFormat, + dataFormatWidth); + if (!dataSurface) { + gfxWarning() << "Failed to create DataSourceSurface."; + return nullptr; + } + gfx::DataSourceSurface::ScopedMap map(dataSurface, + gfx::DataSourceSurface::READ_WRITE); + char* dest = reinterpret_cast(map.GetData()); + if (!mRecorder->WaitForCheckpoint(checkpoint, kGetDataTimeout)) { + gfxWarning() << "Timed out preparing data for DataSourceSurface."; + return dataSurface.forget(); + } + + mRecorder->RecordEvent(RecordedGetDataForSurface(aSurface)); + mRecorder->ReturnRead(dest, ssSize.height * dataFormatWidth); + + return dataSurface.forget(); +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/ipc/CanvasChild.h b/gfx/layers/ipc/CanvasChild.h new file mode 100644 index 000000000000..65ec29744969 --- /dev/null +++ b/gfx/layers/ipc/CanvasChild.h @@ -0,0 +1,117 @@ +/* -*- 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 https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_layers_CanvasChild_h +#define mozilla_layers_CanvasChild_h + +#include "mozilla/gfx/RecordedEvent.h" +#include "mozilla/ipc/CrossProcessSemaphore.h" +#include "mozilla/layers/PCanvasChild.h" +#include "mozilla/layers/SourceSurfaceSharedData.h" +#include "nsRefPtrHashtable.h" +#include "nsTArray.h" + +namespace mozilla { + +namespace gfx { +class SourceSurface; +} + +namespace layers { +class CanvasDrawEventRecorder; + +class CanvasChild final : public PCanvasChild { + public: + NS_INLINE_DECL_REFCOUNTING(CanvasChild) + + explicit CanvasChild(Endpoint&& aEndpoint); + + /** + * Ensures that the DrawEventRecorder has been created. + * + * @params aTextureType the TextureType to create in the CanvasTranslator. + */ + void EnsureRecorder(TextureType aTextureType); + + /** + * Send a messsage to our CanvasParent to resume translation. + */ + void ResumeTranslation(); + + /** + * Clean up IPDL actor. + */ + void Destroy(); + + /** + * Called when a RecordedTextureData is write locked. + */ + void OnTextureWriteLock(); + + /** + * Called when a RecordedTextureData is forwarded to the compositor. + */ + void OnTextureForwarded(); + + /** + * @returns true if we should be caching data surfaces in the GPU process. + */ + bool ShouldCacheDataSurface() const { + return mTransactionsSinceGetDataSurface < kCacheDataSurfaceThreshold; + } + + /** + * Ensures that we have sent a begin transaction event, since the last + * end transaction. + */ + void EnsureBeginTransaction(); + + /** + * Send an end transaction event to indicate the end of events for this frame. + */ + void EndTransaction(); + + /** + * Create a DrawTargetRecording for a canvas texture. + * @param aSize size for the DrawTarget + * @param aFormat SurfaceFormat for the DrawTarget + * @returns newly created DrawTargetRecording + */ + already_AddRefed CreateDrawTarget( + gfx::IntSize aSize, gfx::SurfaceFormat aFormat); + + /** + * Record an event for processing by the CanvasParent's CanvasTranslator. + * @param aEvent the event to record + */ + void RecordEvent(const gfx::RecordedEvent& aEvent); + + already_AddRefed GetDataSurface( + const gfx::SourceSurface* aSurface); + + protected: + void ActorDestroy(ActorDestroyReason aWhy) final; + + private: + DISALLOW_COPY_AND_ASSIGN(CanvasChild); + + ~CanvasChild() final; + + static const uint32_t kCacheDataSurfaceThreshold = 10; + + RefPtr mRecorder; + TextureType mTextureType = TextureType::Unknown; + uint32_t mLastWriteLockCheckpoint = 0; + uint32_t mTransactionsSinceGetDataSurface = kCacheDataSurfaceThreshold; + bool mCanSend = false; + bool mIsInTransaction = false; + bool mHasOutstandingWriteLock = false; +}; + +} // namespace layers +} // namespace mozilla + +#endif // mozilla_layers_CanvasChild_h diff --git a/gfx/layers/ipc/CanvasParent.cpp b/gfx/layers/ipc/CanvasParent.cpp new file mode 100644 index 000000000000..27670d4ddb4a --- /dev/null +++ b/gfx/layers/ipc/CanvasParent.cpp @@ -0,0 +1,125 @@ +/* -*- 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 "CanvasParent.h" + +#include "base/thread.h" +#include "mozilla/layers/SourceSurfaceSharedData.h" +#include "mozilla/layers/TextureClient.h" + +#if defined(XP_WIN) +# include "mozilla/gfx/DeviceManagerDx.h" +# include "mozilla/layers/DeviceAttachmentsD3D11.h" +#endif + +bool NS_IsInCanvasThread() { + return mozilla::layers::CanvasParent::IsInCanvasThread(); +} + +namespace mozilla { +namespace layers { + +static base::Thread* sCanvasThread = nullptr; + +static MessageLoop* CanvasPlaybackLoop() { + if (!sCanvasThread) { + MOZ_ASSERT(NS_IsInCompositorThread()); + base::Thread* canvasThread = new base::Thread("Canvas"); + if (canvasThread->Start()) { + sCanvasThread = canvasThread; + } + } + + return sCanvasThread ? sCanvasThread->message_loop() : MessageLoop::current(); +} + +/* static */ +already_AddRefed CanvasParent::Create( + ipc::Endpoint&& aEndpoint) { + MOZ_ASSERT(NS_IsInCompositorThread()); + + RefPtr canvasParent = new CanvasParent(); + if (CanvasPlaybackLoop()->IsAcceptingTasks()) { + RefPtr runnable = NewRunnableMethod&&>( + "CanvasParent::Bind", canvasParent, &CanvasParent::Bind, + std::move(aEndpoint)); + CanvasPlaybackLoop()->PostTask(runnable.forget()); + } + return do_AddRef(canvasParent); +} + +/* static */ bool CanvasParent::IsInCanvasThread() { + return sCanvasThread && + sCanvasThread->thread_id() == PlatformThread::CurrentId(); +} + +/* static */ void CanvasParent::Shutdown() { + if (sCanvasThread) { + delete sCanvasThread; + sCanvasThread = nullptr; + } +} + +CanvasParent::CanvasParent() {} + +CanvasParent::~CanvasParent() {} + +void CanvasParent::Bind(Endpoint&& aEndpoint) { + if (!aEndpoint.Bind(this)) { + return; + } + + mSelfRef = this; +} + +mozilla::ipc::IPCResult CanvasParent::RecvCreateTranslator( + const TextureType& aTextureType, + const ipc::SharedMemoryBasic::Handle& aReadHandle, + const CrossProcessSemaphoreHandle& aReaderSem, + const CrossProcessSemaphoreHandle& aWriterSem) { + mTranslator = CanvasTranslator::Create(aTextureType, aReadHandle, aReaderSem, + aWriterSem); + return RecvResumeTranslation(); +} + +ipc::IPCResult CanvasParent::RecvResumeTranslation() { + MOZ_ASSERT(mTranslator); + + if (!mTranslator->IsValid()) { + return IPC_FAIL(this, "Canvas Translation failed."); + } + + PostStartTranslationTask(); + + return IPC_OK(); +} + +void CanvasParent::PostStartTranslationTask() { + if (MessageLoop::current()->IsAcceptingTasks()) { + RefPtr runnable = + NewRunnableMethod("CanvasParent::StartTranslation", this, + &CanvasParent::StartTranslation); + MessageLoop::current()->PostTask(runnable.forget()); + } +} + +void CanvasParent::StartTranslation() { + if (!mTranslator->TranslateRecording()) { + PostStartTranslationTask(); + } +} + +UniquePtr +CanvasParent::LookupSurfaceDescriptorForClientDrawTarget( + const uintptr_t aDrawTarget) { + return mTranslator->WaitForSurfaceDescriptor( + reinterpret_cast(aDrawTarget)); +} + +void CanvasParent::DeallocPCanvasParent() { mSelfRef = nullptr; } + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/ipc/CanvasParent.h b/gfx/layers/ipc/CanvasParent.h new file mode 100644 index 000000000000..74b6f8b87396 --- /dev/null +++ b/gfx/layers/ipc/CanvasParent.h @@ -0,0 +1,97 @@ +/* -*- 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 https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_layers_CanvasParent_h +#define mozilla_layers_CanvasParent_h + +#include "mozilla/ipc/CrossProcessSemaphore.h" +#include "mozilla/layers/CanvasTranslator.h" +#include "mozilla/layers/PCanvasParent.h" +#include "mozilla/UniquePtr.h" + +namespace mozilla { +namespace layers { +class TextureData; + +class CanvasParent final : public PCanvasParent { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CanvasParent) + + friend class PProtocolParent; + + /** + * Create a CanvasParent and bind it to the given endpoint on the + * CanvasPlaybackLoop. + * + * @params aEndpoint the endpoint to bind to + * @returns the new CanvasParent + */ + static already_AddRefed Create( + Endpoint&& aEndpoint); + + static bool IsInCanvasThread(); + + /** + * Shutdown the canvas thread. + */ + static void Shutdown(); + + /** + * Create a canvas translator for a particular TextureType, which translates + * events from a CanvasEventRingBuffer. + * + * @param aTextureType the TextureType the translator will create + * @param aReadHandle handle to the shared memory for the + * CanvasEventRingBuffer + * @param aReaderSem reading blocked semaphore for the CanvasEventRingBuffer + * @param aWriterSem writing blocked semaphore for the CanvasEventRingBuffer + */ + ipc::IPCResult RecvCreateTranslator( + const TextureType& aTextureType, + const ipc::SharedMemoryBasic::Handle& aReadHandle, + const CrossProcessSemaphoreHandle& aReaderSem, + const CrossProcessSemaphoreHandle& aWriterSem); + + /** + * Used to tell the CanvasTranslator to start translating again after it has + * stopped due to a timeout waiting for events. + */ + ipc::IPCResult RecvResumeTranslation(); + + void ActorDestroy(ActorDestroyReason why) final {} + + void DeallocPCanvasParent(); + + /** + * Used by the compositor thread to get the SurfaceDescriptor associated with + * the DrawTarget from another process. + * + * @param aDrawTarget the key to find the TextureData + * @returns the SurfaceDescriptor associated with the key + */ + UniquePtr LookupSurfaceDescriptorForClientDrawTarget( + const uintptr_t aDrawTarget); + + private: + CanvasParent(); + ~CanvasParent() final; + + DISALLOW_COPY_AND_ASSIGN(CanvasParent); + + void Bind(Endpoint&& aEndpoint); + + void PostStartTranslationTask(); + + void StartTranslation(); + + RefPtr mSelfRef; + UniquePtr mTranslator; +}; + +} // namespace layers +} // namespace mozilla + +#endif // mozilla_layers_CanvasParent_h diff --git a/gfx/layers/ipc/CompositorBridgeChild.cpp b/gfx/layers/ipc/CompositorBridgeChild.cpp index 66fbf2fffd46..52bab3cce0d1 100644 --- a/gfx/layers/ipc/CompositorBridgeChild.cpp +++ b/gfx/layers/ipc/CompositorBridgeChild.cpp @@ -18,6 +18,7 @@ #include "mozilla/layers/APZChild.h" #include "mozilla/layers/IAPZCTreeManager.h" #include "mozilla/layers/APZCTreeManagerChild.h" +#include "mozilla/layers/CanvasChild.h" #include "mozilla/layers/LayerTransactionChild.h" #include "mozilla/layers/PaintThread.h" #include "mozilla/layers/PLayerTransactionChild.h" @@ -117,6 +118,10 @@ void CompositorBridgeChild::AfterDestroy() { mActorDestroyed = true; } + if (mCanvasChild) { + mCanvasChild->Destroy(); + } + if (sCompositorBridge == this) { sCompositorBridge = nullptr; } @@ -245,6 +250,18 @@ void CompositorBridgeChild::InitForContent(uint32_t aNamespace) { mCanSend = true; mIdNamespace = aNamespace; + + if (gfx::gfxVars::RemoteCanvasEnabled()) { + ipc::Endpoint parentEndpoint; + ipc::Endpoint childEndpoint; + nsresult rv = PCanvas::CreateEndpoints(OtherPid(), base::GetCurrentProcId(), + &parentEndpoint, &childEndpoint); + if (NS_SUCCEEDED(rv)) { + Unused << SendInitPCanvasParent(std::move(parentEndpoint)); + mCanvasChild = new CanvasChild(std::move(childEndpoint)); + } + } + sCompositorBridge = this; } @@ -918,6 +935,16 @@ PTextureChild* CompositorBridgeChild::CreateTexture( LayersId{0} /* FIXME? */, aSerial, aExternalImageId); } +already_AddRefed CompositorBridgeChild::GetCanvasChild() { + return do_AddRef(mCanvasChild); +} + +void CompositorBridgeChild::EndCanvasTransaction() { + if (mCanvasChild) { + mCanvasChild->EndTransaction(); + } +} + bool CompositorBridgeChild::AllocUnsafeShmem( size_t aSize, ipc::SharedMemory::SharedMemoryType aType, ipc::Shmem* aShmem) { diff --git a/gfx/layers/ipc/CompositorBridgeChild.h b/gfx/layers/ipc/CompositorBridgeChild.h index 4493b87f00ab..a4bbdd65d906 100644 --- a/gfx/layers/ipc/CompositorBridgeChild.h +++ b/gfx/layers/ipc/CompositorBridgeChild.h @@ -41,6 +41,7 @@ using mozilla::dom::BrowserChild; class IAPZCTreeManager; class APZCTreeManagerChild; +class CanvasChild; class ClientLayerManager; class CompositorBridgeParent; class CompositorManagerChild; @@ -122,6 +123,10 @@ class CompositorBridgeChild final : public PCompositorBridgeChild, wr::MaybeExternalImageId& aExternalImageId, nsIEventTarget* aTarget) override; + already_AddRefed GetCanvasChild() final; + + void EndCanvasTransaction(); + /** * Request that the parent tell us when graphics are ready on GPU. * When we get that message, we bounce it to the BrowserParent via @@ -391,6 +396,8 @@ class CompositorBridgeChild final : public PCompositorBridgeChild, uintptr_t mSlowFlushCount; uintptr_t mTotalFlushCount; + + RefPtr mCanvasChild; }; } // namespace layers diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index 7c38d72431d7..c4311658fe1d 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -2283,6 +2283,11 @@ bool CompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor) { return TextureHost::DestroyIPDLActor(actor); } +mozilla::ipc::IPCResult CompositorBridgeParent::RecvInitPCanvasParent( + Endpoint&& aEndpoint) { + MOZ_CRASH("PCanvasParent shouldn't be created via CompositorBridgeParent."); +} + bool CompositorBridgeParent::IsSameProcess() const { return OtherPid() == base::GetCurrentProcId(); } diff --git a/gfx/layers/ipc/CompositorBridgeParent.h b/gfx/layers/ipc/CompositorBridgeParent.h index e4edd90acc2b..1f8f596555c5 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.h +++ b/gfx/layers/ipc/CompositorBridgeParent.h @@ -85,6 +85,7 @@ class PAPZParent; class ContentCompositorBridgeParent; class CompositorThreadHolder; class InProcessCompositorSession; +class TextureData; class WebRenderBridgeParent; struct ScopedLayerTreeRegistration { @@ -188,6 +189,11 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent, virtual bool IsRemote() const { return false; } + virtual UniquePtr + LookupSurfaceDescriptorForClientDrawTarget(const uintptr_t aDrawTarget) { + MOZ_CRASH("Should only be called on ContentCompositorBridgeParent."); + } + virtual void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr) { MOZ_CRASH(); @@ -265,6 +271,8 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent, const uint32_t& startIndex, nsTArray* intervals) = 0; virtual mozilla::ipc::IPCResult RecvCheckContentOnlyTDR( const uint32_t& sequenceNum, bool* isContentOnlyTDR) = 0; + virtual mozilla::ipc::IPCResult RecvInitPCanvasParent( + Endpoint&& aEndpoint) = 0; bool mCanSend; @@ -388,6 +396,9 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase, const wr::MaybeExternalImageId& aExternalImageId) override; bool DeallocPTextureParent(PTextureParent* actor) override; + mozilla::ipc::IPCResult RecvInitPCanvasParent( + Endpoint&& aEndpoint) final; + bool IsSameProcess() const override; void NotifyWebRenderContextPurge(); diff --git a/gfx/layers/ipc/CompositorThread.cpp b/gfx/layers/ipc/CompositorThread.cpp index feef1bdf1430..aba040568ce3 100644 --- a/gfx/layers/ipc/CompositorThread.cpp +++ b/gfx/layers/ipc/CompositorThread.cpp @@ -7,6 +7,7 @@ #include "MainThreadUtils.h" #include "nsThreadUtils.h" #include "CompositorBridgeParent.h" +#include "mozilla/layers/CanvasParent.h" #include "mozilla/layers/CompositorManagerParent.h" #include "mozilla/layers/ImageBridgeParent.h" #include "mozilla/media/MediaSystemResourceService.h" @@ -127,6 +128,7 @@ void CompositorThreadHolder::Shutdown() { gfx::ReleaseVRManagerParentSingleton(); MediaSystemResourceService::Shutdown(); CompositorManagerParent::Shutdown(); + CanvasParent::Shutdown(); sCompositorThreadHolder = nullptr; diff --git a/gfx/layers/ipc/ContentCompositorBridgeParent.cpp b/gfx/layers/ipc/ContentCompositorBridgeParent.cpp index 1a097250c4c1..4648db3d76e0 100644 --- a/gfx/layers/ipc/ContentCompositorBridgeParent.cpp +++ b/gfx/layers/ipc/ContentCompositorBridgeParent.cpp @@ -22,6 +22,7 @@ #include "mozilla/layers/APZCTreeManagerParent.h" // for APZCTreeManagerParent #include "mozilla/layers/APZUpdater.h" // for APZUpdater #include "mozilla/layers/AsyncCompositionManager.h" +#include "mozilla/layers/CanvasParent.h" #include "mozilla/layers/CompositorOptions.h" #include "mozilla/layers/CompositorThread.h" #include "mozilla/layers/LayerManagerComposite.h" @@ -614,6 +615,22 @@ bool ContentCompositorBridgeParent::DeallocPTextureParent( return TextureHost::DestroyIPDLActor(actor); } +mozilla::ipc::IPCResult ContentCompositorBridgeParent::RecvInitPCanvasParent( + Endpoint&& aEndpoint) { + MOZ_RELEASE_ASSERT(!mCanvasParent, + "Canvas Parent should only be created once per " + "CrossProcessCompositorBridgeParent."); + + mCanvasParent = CanvasParent::Create(std::move(aEndpoint)); + return IPC_OK(); +} + +UniquePtr +ContentCompositorBridgeParent::LookupSurfaceDescriptorForClientDrawTarget( + const uintptr_t aDrawTarget) { + return mCanvasParent->LookupSurfaceDescriptorForClientDrawTarget(aDrawTarget); +} + bool ContentCompositorBridgeParent::IsSameProcess() const { return OtherPid() == base::GetCurrentProcId(); } diff --git a/gfx/layers/ipc/ContentCompositorBridgeParent.h b/gfx/layers/ipc/ContentCompositorBridgeParent.h index c2abc506e316..d322a4c4e507 100644 --- a/gfx/layers/ipc/ContentCompositorBridgeParent.h +++ b/gfx/layers/ipc/ContentCompositorBridgeParent.h @@ -9,10 +9,12 @@ #include "mozilla/layers/CompositorBridgeParent.h" #include "mozilla/layers/CompositorThread.h" +#include "mozilla/UniquePtr.h" namespace mozilla { namespace layers { +class CanvasParent; class CompositorOptions; /** @@ -153,6 +155,9 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase { bool DeallocPTextureParent(PTextureParent* actor) override; + mozilla::ipc::IPCResult RecvInitPCanvasParent( + Endpoint&& aEndpoint) final; + bool IsSameProcess() const override; PCompositorWidgetParent* AllocPCompositorWidgetParent( @@ -188,6 +193,9 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase { bool IsRemote() const override { return true; } + UniquePtr LookupSurfaceDescriptorForClientDrawTarget( + const uintptr_t aDrawTarget) final; + private: // Private destructor, to discourage deletion outside of Release(): virtual ~ContentCompositorBridgeParent(); @@ -203,6 +211,8 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase { // transaction is received bool mNotifyAfterRemotePaint; bool mDestroyCalled; + + RefPtr mCanvasParent; }; } // namespace layers diff --git a/gfx/layers/ipc/LayersSurfaces.ipdlh b/gfx/layers/ipc/LayersSurfaces.ipdlh index 4d1f91d45aaa..00e4d92a3c05 100644 --- a/gfx/layers/ipc/LayersSurfaces.ipdlh +++ b/gfx/layers/ipc/LayersSurfaces.ipdlh @@ -133,6 +133,10 @@ struct SurfaceDescriptorShared Handle handle; }; +struct SurfaceDescriptorRecorded { + uintptr_t drawTarget; +}; + union SurfaceDescriptor { SurfaceDescriptorBuffer; SurfaceDescriptorDIB; @@ -145,6 +149,7 @@ union SurfaceDescriptor { SurfaceDescriptorMacIOSurface; SurfaceDescriptorSharedGLTexture; SurfaceDescriptorGPUVideo; + SurfaceDescriptorRecorded; null_t; }; diff --git a/gfx/layers/ipc/PCanvas.ipdl b/gfx/layers/ipc/PCanvas.ipdl new file mode 100644 index 000000000000..aa586580ab8c --- /dev/null +++ b/gfx/layers/ipc/PCanvas.ipdl @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=8 et : */ +/* 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/. */ + +using mozilla::CrossProcessSemaphoreHandle from "mozilla/ipc/CrossProcessSemaphore.h"; +using mozilla::layers::TextureType from "mozilla/layers/LayersTypes.h"; +using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasic.h"; + +namespace mozilla { +namespace layers { + +/** + * PCanvas is the IPDL for recorded Canvas drawing. + */ +sync protocol PCanvas { +parent: + /** + * Create a CanvasTranslator for a particular TextureType, which translates + * events from a CanvasEventRingBuffer. aReadHandle is the shared memory + * handle for the ring buffer. aReaderSem and aWriterSem are handles for the + * semaphores to handle waiting on either side. + */ + async CreateTranslator(TextureType aTextureType, Handle aReadHandle, + CrossProcessSemaphoreHandle aReaderSem, + CrossProcessSemaphoreHandle aWriterSem); + + /** + * Used to tell the CanvasTranslator to start translating again after it has + * stopped due to a timeout waiting for events. + */ + async ResumeTranslation(); +}; + +} // layers +} // mozilla diff --git a/gfx/layers/ipc/PCompositorBridge.ipdl b/gfx/layers/ipc/PCompositorBridge.ipdl index e3510b55ff97..690c7cdf22e1 100644 --- a/gfx/layers/ipc/PCompositorBridge.ipdl +++ b/gfx/layers/ipc/PCompositorBridge.ipdl @@ -11,6 +11,7 @@ include PlatformWidgetTypes; include protocol PAPZ; include protocol PAPZCTreeManager; include protocol PBrowser; +include protocol PCanvas; include protocol PCompositorManager; include protocol PCompositorWidget; include protocol PLayerTransaction; @@ -255,6 +256,8 @@ parent: async PTexture(SurfaceDescriptor aSharedData, ReadLockDescriptor aReadLock, LayersBackend aBackend, TextureFlags aTextureFlags, LayersId id, uint64_t aSerial, MaybeExternalImageId aExternalImageId); + async InitPCanvasParent(Endpoint aEndpoint); + sync SyncWithCompositor(); // The pipelineId is the same as the layersId diff --git a/gfx/layers/ipc/TextureForwarder.h b/gfx/layers/ipc/TextureForwarder.h index 5b4e7332248b..49fd4a5ed013 100644 --- a/gfx/layers/ipc/TextureForwarder.h +++ b/gfx/layers/ipc/TextureForwarder.h @@ -19,6 +19,7 @@ namespace ipc { class IShmemAllocator; } namespace layers { +class CanvasChild; /** * An abstract interface for classes that implement the autogenerated @@ -78,6 +79,11 @@ class TextureForwarder : public LayersIPCChannel { LayersBackend aLayersBackend, TextureFlags aFlags, uint64_t aSerial, wr::MaybeExternalImageId& aExternalImageId, nsIEventTarget* aTarget = nullptr) = 0; + + /** + * Returns the CanvasChild for this TextureForwarder. + */ + virtual already_AddRefed GetCanvasChild() { return nullptr; }; }; } // namespace layers diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index d2f383da867b..7929d6ebf0d4 100755 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -130,7 +130,9 @@ EXPORTS.mozilla.layers += [ 'basic/TextureHostBasic.h', 'BSPTree.h', 'BufferTexture.h', + 'CanvasDrawEventRecorder.h', 'CanvasRenderer.h', + 'CanvasTranslator.h', 'client/CanvasClient.h', 'client/CompositableClient.h', 'client/ContentClient.h', @@ -142,6 +144,7 @@ EXPORTS.mozilla.layers += [ 'client/TextureClientPool.h', 'client/TextureClientRecycleAllocator.h', 'client/TextureClientSharedSurface.h', + 'client/TextureRecorded.h', 'client/TiledContentClient.h', 'composite/AsyncCompositionManager.h', 'composite/CanvasLayerComposite.h', @@ -176,6 +179,8 @@ EXPORTS.mozilla.layers += [ 'ipc/APZCTreeManagerParent.h', 'ipc/APZInputBridgeChild.h', 'ipc/APZInputBridgeParent.h', + 'ipc/CanvasChild.h', + 'ipc/CanvasParent.h', 'ipc/CompositableForwarder.h', 'ipc/CompositableTransactionParent.h', 'ipc/CompositorBridgeChild.h', @@ -371,7 +376,9 @@ UNIFIED_SOURCES += [ 'basic/TextureHostBasic.cpp', 'BSPTree.cpp', 'BufferTexture.cpp', + 'CanvasDrawEventRecorder.cpp', 'CanvasRenderer.cpp', + 'CanvasTranslator.cpp', 'client/CanvasClient.cpp', 'client/ClientCanvasLayer.cpp', 'client/ClientCanvasRenderer.cpp', @@ -391,6 +398,7 @@ UNIFIED_SOURCES += [ 'client/TextureClientPool.cpp', 'client/TextureClientRecycleAllocator.cpp', 'client/TextureClientSharedSurface.cpp', + 'client/TextureRecorded.cpp', 'client/TiledContentClient.cpp', 'composite/AsyncCompositionManager.cpp', 'composite/CanvasLayerComposite.cpp', @@ -424,6 +432,8 @@ UNIFIED_SOURCES += [ 'ipc/APZCTreeManagerParent.cpp', 'ipc/APZInputBridgeChild.cpp', 'ipc/APZInputBridgeParent.cpp', + 'ipc/CanvasChild.cpp', + 'ipc/CanvasParent.cpp', 'ipc/CompositableTransactionParent.cpp', 'ipc/CompositorBench.cpp', 'ipc/CompositorBridgeChild.cpp', @@ -540,6 +550,7 @@ IPDL_SOURCES += [ 'ipc/PAPZ.ipdl', 'ipc/PAPZCTreeManager.ipdl', 'ipc/PAPZInputBridge.ipdl', + 'ipc/PCanvas.ipdl', 'ipc/PCompositorBridge.ipdl', 'ipc/PCompositorManager.ipdl', 'ipc/PImageBridge.ipdl', diff --git a/gfx/layers/wr/WebRenderLayerManager.cpp b/gfx/layers/wr/WebRenderLayerManager.cpp index e1c490b7dcf0..8b7ed3b0b4da 100644 --- a/gfx/layers/wr/WebRenderLayerManager.cpp +++ b/gfx/layers/wr/WebRenderLayerManager.cpp @@ -245,6 +245,8 @@ bool WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags) { } } + GetCompositorBridgeChild()->EndCanvasTransaction(); + AutoTArray renderRootUpdates; for (auto& stateManager : mStateManagers) { auto renderRoot = stateManager.GetRenderRoot(); @@ -428,6 +430,8 @@ void WebRenderLayerManager::EndTransactionWithoutLayer( } } + GetCompositorBridgeChild()->EndCanvasTransaction(); + { AUTO_PROFILER_TRACING("Paint", "ForwardDPTransaction", GRAPHICS); InfallibleTArray renderRootDLs; diff --git a/xpcom/threads/nsThreadUtils.h b/xpcom/threads/nsThreadUtils.h index 77004e738a79..404c2e6d1a37 100644 --- a/xpcom/threads/nsThreadUtils.h +++ b/xpcom/threads/nsThreadUtils.h @@ -369,6 +369,8 @@ bool SpinEventLoopUntil(Pred&& aPredicate, nsIThread* aThread = nullptr) { */ extern bool NS_IsInCompositorThread(); +extern bool NS_IsInCanvasThread(); + extern bool NS_IsInVRThread(); //----------------------------------------------------------------------------- From 3cec9dbf001821071e85647b0f6df23548d24668 Mon Sep 17 00:00:00 2001 From: Bob Owen Date: Sun, 2 Dec 2018 14:19:52 +0000 Subject: [PATCH 15/22] Bug 1464032 Part 13: Make the recording of surface data more efficient. r=rhunt --- gfx/2d/RecordedEventImpl.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gfx/2d/RecordedEventImpl.h b/gfx/2d/RecordedEventImpl.h index 07d084897e36..42ac18b9d215 100644 --- a/gfx/2d/RecordedEventImpl.h +++ b/gfx/2d/RecordedEventImpl.h @@ -2803,9 +2803,10 @@ void RecordedSourceSurfaceCreation::Record(S& aStream) const { WriteElement(aStream, mSize); WriteElement(aStream, mFormat); MOZ_ASSERT(mData); - for (int y = 0; y < mSize.height; y++) { - aStream.write((const char*)mData + y * mStride, - BytesPerPixel(mFormat) * mSize.width); + size_t dataFormatWidth = BytesPerPixel(mFormat) * mSize.width; + const char* endSrc = (const char*)(mData + (mSize.height * mStride)); + for (const char* src = (const char*)mData; src < endSrc; src += mStride) { + aStream.write(src, dataFormatWidth); } } From 944d106bbf7eeccf8258e5b08b65ec462eef876c Mon Sep 17 00:00:00 2001 From: Bob Owen Date: Sun, 2 Dec 2018 14:20:00 +0000 Subject: [PATCH 16/22] Bug 1464032 Part 14: Refactor Path recording to record Arc properly. r=jrmuizel This also improves the recording and translation speeds. --- gfx/2d/PathHelpers.h | 3 +- gfx/2d/PathRecording.cpp | 197 +++++++++++++++++++++++++++++-------- gfx/2d/PathRecording.h | 195 ++++++++++++++++++++++++++---------- gfx/2d/RecordedEvent.h | 3 - gfx/2d/RecordedEventImpl.h | 75 +++----------- gfx/2d/RecordingTypes.h | 21 ++++ 6 files changed, 333 insertions(+), 161 deletions(-) diff --git a/gfx/2d/PathHelpers.h b/gfx/2d/PathHelpers.h index 4fdfeb08ec31..9223b032bcf4 100644 --- a/gfx/2d/PathHelpers.h +++ b/gfx/2d/PathHelpers.h @@ -123,7 +123,7 @@ inline void AcuteArcToBezier(T* aSink, const Point& aOrigin, template void ArcToBezier(T* aSink, const Point& aOrigin, const Size& aRadius, float aStartAngle, float aEndAngle, bool aAntiClockwise, - float aRotation = 0.0f) { + float aRotation = 0.0f, const Matrix& aTransform = Matrix()) { Float sweepDirection = aAntiClockwise ? -1.0f : 1.0f; // Calculate the total arc we're going to sweep. @@ -148,6 +148,7 @@ void ArcToBezier(T* aSink, const Point& aOrigin, const Size& aRadius, transform *= Matrix::Rotation(aRotation); } transform.PostTranslate(aOrigin); + transform *= aTransform; aSink->LineTo(transform.TransformPoint(currentStartOffset)); while (arcSweepLeft > 0) { diff --git a/gfx/2d/PathRecording.cpp b/gfx/2d/PathRecording.cpp index 4512a91543e2..2f9f05522e7a 100644 --- a/gfx/2d/PathRecording.cpp +++ b/gfx/2d/PathRecording.cpp @@ -11,55 +11,183 @@ namespace mozilla { namespace gfx { +#define NEXT_PARAMS(_type) \ + const _type params = *reinterpret_cast(nextByte); \ + nextByte += sizeof(_type); + using namespace std; +bool PathOps::StreamToSink(PathSink& aPathSink) const { + if (mPathData.empty()) { + return true; + } + + const uint8_t* nextByte = mPathData.data(); + const uint8_t* end = nextByte + mPathData.size(); + while (nextByte < end) { + const OpType opType = *reinterpret_cast(nextByte); + nextByte += sizeof(OpType); + switch (opType) { + case OpType::OP_MOVETO: { + NEXT_PARAMS(Point) + aPathSink.MoveTo(params); + break; + } + case OpType::OP_LINETO: { + NEXT_PARAMS(Point) + aPathSink.LineTo(params); + break; + } + case OpType::OP_BEZIERTO: { + NEXT_PARAMS(ThreePoints) + aPathSink.BezierTo(params.p1, params.p2, params.p3); + break; + } + case OpType::OP_QUADRATICBEZIERTO: { + NEXT_PARAMS(TwoPoints) + aPathSink.QuadraticBezierTo(params.p1, params.p2); + break; + } + case OpType::OP_ARC: { + NEXT_PARAMS(ArcParams) + aPathSink.Arc(params.origin, params.radius, params.startAngle, + params.endAngle, params.antiClockwise); + break; + } + case OpType::OP_CLOSE: + aPathSink.Close(); + break; + default: + return false; + } + } + + return true; +} + +PathOps PathOps::TransformedCopy(const Matrix& aTransform) const { + PathOps newPathOps; + const uint8_t* nextByte = mPathData.data(); + const uint8_t* end = nextByte + mPathData.size(); + while (nextByte < end) { + const OpType opType = *reinterpret_cast(nextByte); + nextByte += sizeof(OpType); + switch (opType) { + case OpType::OP_MOVETO: { + NEXT_PARAMS(Point) + newPathOps.MoveTo(aTransform.TransformPoint(params)); + break; + } + case OpType::OP_LINETO: { + NEXT_PARAMS(Point) + newPathOps.LineTo(aTransform.TransformPoint(params)); + break; + } + case OpType::OP_BEZIERTO: { + NEXT_PARAMS(ThreePoints) + newPathOps.BezierTo(aTransform.TransformPoint(params.p1), + aTransform.TransformPoint(params.p2), + aTransform.TransformPoint(params.p3)); + break; + } + case OpType::OP_QUADRATICBEZIERTO: { + NEXT_PARAMS(TwoPoints) + newPathOps.QuadraticBezierTo(aTransform.TransformPoint(params.p1), + aTransform.TransformPoint(params.p2)); + break; + } + case OpType::OP_ARC: { + NEXT_PARAMS(ArcParams) + ArcToBezier(&newPathOps, params.origin, + gfx::Size(params.radius, params.radius), params.startAngle, + params.endAngle, params.antiClockwise, 0.0f, aTransform); + break; + } + case OpType::OP_CLOSE: + newPathOps.Close(); + break; + default: + MOZ_CRASH("We control mOpTypes, so this should never happen."); + } + } + + return newPathOps; +} + +#undef NEXT_PARAMS + +size_t PathOps::NumberOfOps() const { + size_t size = 0; + const uint8_t* nextByte = mPathData.data(); + const uint8_t* end = nextByte + mPathData.size(); + while (nextByte < end) { + size++; + const OpType opType = *reinterpret_cast(nextByte); + nextByte += sizeof(OpType); + switch (opType) { + case OpType::OP_MOVETO: + nextByte += sizeof(Point); + break; + case OpType::OP_LINETO: + nextByte += sizeof(Point); + break; + case OpType::OP_BEZIERTO: + nextByte += sizeof(ThreePoints); + break; + case OpType::OP_QUADRATICBEZIERTO: + nextByte += sizeof(TwoPoints); + break; + case OpType::OP_ARC: + nextByte += sizeof(ArcParams); + break; + case OpType::OP_CLOSE: + break; + default: + MOZ_CRASH("We control mOpTypes, so this should never happen."); + } + } + + return size; +} + void PathBuilderRecording::MoveTo(const Point& aPoint) { - PathOp op; - op.mType = PathOp::OP_MOVETO; - op.mP1 = aPoint; - mPathOps.push_back(op); + mPathOps.MoveTo(aPoint); mPathBuilder->MoveTo(aPoint); } void PathBuilderRecording::LineTo(const Point& aPoint) { - PathOp op; - op.mType = PathOp::OP_LINETO; - op.mP1 = aPoint; - mPathOps.push_back(op); + mPathOps.LineTo(aPoint); mPathBuilder->LineTo(aPoint); } void PathBuilderRecording::BezierTo(const Point& aCP1, const Point& aCP2, const Point& aCP3) { - PathOp op; - op.mType = PathOp::OP_BEZIERTO; - op.mP1 = aCP1; - op.mP2 = aCP2; - op.mP3 = aCP3; - mPathOps.push_back(op); + mPathOps.BezierTo(aCP1, aCP2, aCP3); mPathBuilder->BezierTo(aCP1, aCP2, aCP3); } void PathBuilderRecording::QuadraticBezierTo(const Point& aCP1, const Point& aCP2) { - PathOp op; - op.mType = PathOp::OP_QUADRATICBEZIERTO; - op.mP1 = aCP1; - op.mP2 = aCP2; - mPathOps.push_back(op); + mPathOps.QuadraticBezierTo(aCP1, aCP2); mPathBuilder->QuadraticBezierTo(aCP1, aCP2); } void PathBuilderRecording::Close() { - PathOp op; - op.mType = PathOp::OP_CLOSE; - mPathOps.push_back(op); + mPathOps.Close(); mPathBuilder->Close(); } +void PathBuilderRecording::Arc(const Point& aOrigin, float aRadius, + float aStartAngle, float aEndAngle, + bool aAntiClockwise) { + mPathOps.Arc(aOrigin, aRadius, aStartAngle, aEndAngle, aAntiClockwise); + mPathBuilder->Arc(aOrigin, aRadius, aStartAngle, aEndAngle, aAntiClockwise); +} + already_AddRefed PathBuilderRecording::Finish() { RefPtr path = mPathBuilder->Finish(); - return MakeAndAddRef(path, mPathOps, mFillRule, mCurrentPoint, mBeginPoint); + return MakeAndAddRef(path, std::move(mPathOps), mFillRule, + mCurrentPoint, mBeginPoint); } PathRecording::~PathRecording() { @@ -73,8 +201,7 @@ already_AddRefed PathRecording::CopyToBuilder( FillRule aFillRule) const { RefPtr pathBuilder = mPath->CopyToBuilder(aFillRule); RefPtr recording = - new PathBuilderRecording(pathBuilder, aFillRule); - recording->mPathOps = mPathOps; + new PathBuilderRecording(pathBuilder, mPathOps, aFillRule); recording->SetCurrentPoint(mCurrentPoint); recording->SetBeginPoint(mBeginPoint); return recording.forget(); @@ -84,24 +211,8 @@ already_AddRefed PathRecording::TransformedCopyToBuilder( const Matrix& aTransform, FillRule aFillRule) const { RefPtr pathBuilder = mPath->TransformedCopyToBuilder(aTransform, aFillRule); - RefPtr recording = - new PathBuilderRecording(pathBuilder, aFillRule); - typedef std::vector pathOpVec; - for (pathOpVec::const_iterator iter = mPathOps.begin(); - iter != mPathOps.end(); iter++) { - PathOp newPathOp; - newPathOp.mType = iter->mType; - if (sPointCount[newPathOp.mType] >= 1) { - newPathOp.mP1 = aTransform.TransformPoint(iter->mP1); - } - if (sPointCount[newPathOp.mType] >= 2) { - newPathOp.mP2 = aTransform.TransformPoint(iter->mP2); - } - if (sPointCount[newPathOp.mType] >= 3) { - newPathOp.mP3 = aTransform.TransformPoint(iter->mP3); - } - recording->mPathOps.push_back(newPathOp); - } + RefPtr recording = new PathBuilderRecording( + pathBuilder, mPathOps.TransformedCopy(aTransform), aFillRule); recording->SetCurrentPoint(aTransform.TransformPoint(mCurrentPoint)); recording->SetBeginPoint(aTransform.TransformPoint(mBeginPoint)); diff --git a/gfx/2d/PathRecording.h b/gfx/2d/PathRecording.h index 7d32448b79d0..25fc61fc9704 100644 --- a/gfx/2d/PathRecording.h +++ b/gfx/2d/PathRecording.h @@ -12,123 +12,218 @@ #include #include "PathHelpers.h" +#include "RecordingTypes.h" namespace mozilla { namespace gfx { +class PathOps { + public: + PathOps() {} + + template + explicit PathOps(S& aStream); + + PathOps(PathOps&& aOther) : mPathData(std::move(aOther.mPathData)) {} + + PathOps(const PathOps& aOther) : mPathData(aOther.mPathData) {} + + PathOps& operator=(PathOps&& aOther) { + mPathData = std::move(aOther.mPathData); + return *this; + } + + template + void Record(S& aStream) const; + + bool StreamToSink(PathSink& aPathSink) const; + + PathOps TransformedCopy(const Matrix& aTransform) const; + + size_t NumberOfOps() const; + + void MoveTo(const Point& aPoint) { AppendPathOp(OpType::OP_MOVETO, aPoint); } + + void LineTo(const Point& aPoint) { AppendPathOp(OpType::OP_LINETO, aPoint); } + + void BezierTo(const Point& aCP1, const Point& aCP2, const Point& aCP3) { + AppendPathOp(OpType::OP_BEZIERTO, ThreePoints{aCP1, aCP2, aCP3}); + } + + void QuadraticBezierTo(const Point& aCP1, const Point& aCP2) { + AppendPathOp(OpType::OP_QUADRATICBEZIERTO, TwoPoints{aCP1, aCP2}); + } + + void Arc(const Point& aOrigin, float aRadius, float aStartAngle, + float aEndAngle, bool aAntiClockwise) { + AppendPathOp(OpType::OP_ARC, ArcParams{aOrigin, aRadius, aStartAngle, + aEndAngle, aAntiClockwise}); + } + + void Close() { + size_t oldSize = mPathData.size(); + mPathData.resize(oldSize + sizeof(OpType)); + *reinterpret_cast(mPathData.data() + oldSize) = OpType::OP_CLOSE; + } + + private: + void operator=(const PathOps&) = delete; // assign using std::move()! + + enum class OpType : uint32_t { + OP_MOVETO = 0, + OP_LINETO, + OP_BEZIERTO, + OP_QUADRATICBEZIERTO, + OP_ARC, + OP_CLOSE, + OP_INVALID + }; + + template + void AppendPathOp(const OpType& aOpType, const T& aOpParams) { + size_t oldSize = mPathData.size(); + mPathData.resize(oldSize + sizeof(OpType) + sizeof(T)); + memcpy(mPathData.data() + oldSize, &aOpType, sizeof(OpType)); + oldSize += sizeof(OpType); + memcpy(mPathData.data() + oldSize, &aOpParams, sizeof(T)); + } + + struct TwoPoints { + Point p1; + Point p2; + }; + + struct ThreePoints { + Point p1; + Point p2; + Point p3; + }; + + struct ArcParams { + Point origin; + float radius; + float startAngle; + float endAngle; + bool antiClockwise; + }; + + std::vector mPathData; +}; + +template +PathOps::PathOps(S& aStream) { + ReadVector(aStream, mPathData); +} + +template +inline void PathOps::Record(S& aStream) const { + WriteVector(aStream, mPathData); +} + class PathRecording; class DrawEventRecorderPrivate; -class PathBuilderRecording : public PathBuilder { +class PathBuilderRecording final : public PathBuilder { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathBuilderRecording, override) PathBuilderRecording(PathBuilder* aBuilder, FillRule aFillRule) : mPathBuilder(aBuilder), mFillRule(aFillRule) {} + PathBuilderRecording(PathBuilder* aBuilder, const PathOps& aPathOps, + FillRule aFillRule) + : mPathBuilder(aBuilder), mFillRule(aFillRule), mPathOps(aPathOps) {} + /* Move the current point in the path, any figure currently being drawn will * be considered closed during fill operations, however when stroking the * closing line segment will not be drawn. */ - virtual void MoveTo(const Point& aPoint) override; + void MoveTo(const Point& aPoint) final; + /* Add a linesegment to the current figure */ - virtual void LineTo(const Point& aPoint) override; + void LineTo(const Point& aPoint) final; + /* Add a cubic bezier curve to the current figure */ - virtual void BezierTo(const Point& aCP1, const Point& aCP2, - const Point& aCP3) override; + void BezierTo(const Point& aCP1, const Point& aCP2, const Point& aCP3) final; + /* Add a quadratic bezier curve to the current figure */ - virtual void QuadraticBezierTo(const Point& aCP1, const Point& aCP2) override; + void QuadraticBezierTo(const Point& aCP1, const Point& aCP2) final; + /* Close the current figure, this will essentially generate a line segment * from the current point to the starting point for the current figure */ - virtual void Close() override; + void Close() final; /* Add an arc to the current figure */ - virtual void Arc(const Point& aOrigin, float aRadius, float aStartAngle, - float aEndAngle, bool aAntiClockwise) override { - ArcToBezier(this, aOrigin, Size(aRadius, aRadius), aStartAngle, aEndAngle, - aAntiClockwise); - } + void Arc(const Point& aOrigin, float aRadius, float aStartAngle, + float aEndAngle, bool aAntiClockwise) final; /* Point the current subpath is at - or where the next subpath will start * if there is no active subpath. */ - virtual Point CurrentPoint() const override { + Point CurrentPoint() const final { return mPathBuilder->CurrentPoint(); } - virtual Point BeginPoint() const override { + Point BeginPoint() const final { return mPathBuilder->BeginPoint(); } - virtual void SetCurrentPoint(const Point& aPoint) override { + void SetCurrentPoint(const Point& aPoint) final { mPathBuilder->SetCurrentPoint(aPoint); } - virtual void SetBeginPoint(const Point& aPoint) override { + void SetBeginPoint(const Point& aPoint) final { mPathBuilder->SetBeginPoint(aPoint); } - virtual already_AddRefed Finish() override; + already_AddRefed Finish() final; - virtual BackendType GetBackendType() const override { - return BackendType::RECORDING; - } + BackendType GetBackendType() const final { return BackendType::RECORDING; } private: - friend class PathRecording; - RefPtr mPathBuilder; FillRule mFillRule; - std::vector mPathOps; + PathOps mPathOps; }; -class PathRecording : public Path { +class PathRecording final : public Path { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathRecording, override) - PathRecording(Path* aPath, const std::vector aOps, FillRule aFillRule, + PathRecording(Path* aPath, PathOps&& aOps, FillRule aFillRule, const Point& aCurrentPoint, const Point& aBeginPoint) - : mPath(aPath), mPathOps(aOps), mFillRule(aFillRule), + : mPath(aPath), mPathOps(std::move(aOps)), mFillRule(aFillRule), mCurrentPoint(aCurrentPoint), mBeginPoint(aBeginPoint) {} ~PathRecording(); - virtual BackendType GetBackendType() const override { - return BackendType::RECORDING; - } - virtual already_AddRefed CopyToBuilder( - FillRule aFillRule) const override; - virtual already_AddRefed TransformedCopyToBuilder( - const Matrix& aTransform, FillRule aFillRule) const override; - virtual bool ContainsPoint(const Point& aPoint, - const Matrix& aTransform) const override { + BackendType GetBackendType() const final { return BackendType::RECORDING; } + already_AddRefed CopyToBuilder(FillRule aFillRule) const final; + already_AddRefed TransformedCopyToBuilder( + const Matrix& aTransform, FillRule aFillRule) const final; + bool ContainsPoint(const Point& aPoint, + const Matrix& aTransform) const final { return mPath->ContainsPoint(aPoint, aTransform); } - virtual bool StrokeContainsPoint(const StrokeOptions& aStrokeOptions, - const Point& aPoint, - const Matrix& aTransform) const override { + bool StrokeContainsPoint(const StrokeOptions& aStrokeOptions, + const Point& aPoint, + const Matrix& aTransform) const final { return mPath->StrokeContainsPoint(aStrokeOptions, aPoint, aTransform); } - virtual Rect GetBounds(const Matrix& aTransform = Matrix()) const override { + Rect GetBounds(const Matrix& aTransform = Matrix()) const final { return mPath->GetBounds(aTransform); } - virtual Rect GetStrokedBounds( - const StrokeOptions& aStrokeOptions, - const Matrix& aTransform = Matrix()) const override { + Rect GetStrokedBounds(const StrokeOptions& aStrokeOptions, + const Matrix& aTransform = Matrix()) const final { return mPath->GetStrokedBounds(aStrokeOptions, aTransform); } - virtual void StreamToSink(PathSink* aSink) const override { - mPath->StreamToSink(aSink); - } + void StreamToSink(PathSink* aSink) const final { mPath->StreamToSink(aSink); } - virtual FillRule GetFillRule() const override { return mFillRule; } - - void StorePath(std::ostream& aStream) const; - static void ReadPathToBuilder(std::istream& aStream, PathBuilder* aBuilder); + FillRule GetFillRule() const final { return mFillRule; } private: friend class DrawTargetWrapAndRecord; @@ -136,7 +231,7 @@ class PathRecording : public Path { friend class RecordedPathCreation; RefPtr mPath; - std::vector mPathOps; + PathOps mPathOps; FillRule mFillRule; Point mCurrentPoint; Point mBeginPoint; diff --git a/gfx/2d/RecordedEvent.h b/gfx/2d/RecordedEvent.h index 4826702bbf3c..5ccf8b6dad23 100644 --- a/gfx/2d/RecordedEvent.h +++ b/gfx/2d/RecordedEvent.h @@ -18,9 +18,6 @@ namespace mozilla { namespace gfx { -struct PathOp; -class PathRecording; - const uint32_t kMagicInt = 0xc001feed; // A change in major revision means a change in event binary format, causing diff --git a/gfx/2d/RecordedEventImpl.h b/gfx/2d/RecordedEventImpl.h index 42ac18b9d215..b6b94ea896ca 100644 --- a/gfx/2d/RecordedEventImpl.h +++ b/gfx/2d/RecordedEventImpl.h @@ -809,7 +809,6 @@ class RecordedDrawFilter : public RecordedDrawingEvent { class RecordedPathCreation : public RecordedEventDerived { public: MOZ_IMPLICIT RecordedPathCreation(PathRecording* aPath); - ~RecordedPathCreation(); bool PlayEvent(Translator* aTranslator) const override; @@ -824,7 +823,8 @@ class RecordedPathCreation : public RecordedEventDerived { ReferencePtr mRefPtr; FillRule mFillRule; - std::vector mPathOps; + RefPtr mPath; + UniquePtr mPathOps; template MOZ_IMPLICIT RecordedPathCreation(S& aStream); @@ -2668,36 +2668,13 @@ inline RecordedPathCreation::RecordedPathCreation(PathRecording* aPath) : RecordedEventDerived(PATHCREATION), mRefPtr(aPath), mFillRule(aPath->mFillRule), - mPathOps(aPath->mPathOps) {} - -inline RecordedPathCreation::~RecordedPathCreation() {} + mPath(aPath) {} inline bool RecordedPathCreation::PlayEvent(Translator* aTranslator) const { RefPtr builder = aTranslator->GetReferenceDrawTarget()->CreatePathBuilder(mFillRule); - - for (size_t i = 0; i < mPathOps.size(); i++) { - const PathOp& op = mPathOps[i]; - switch (op.mType) { - case PathOp::OP_MOVETO: - builder->MoveTo(op.mP1); - break; - case PathOp::OP_LINETO: - builder->LineTo(op.mP1); - break; - case PathOp::OP_BEZIERTO: - builder->BezierTo(op.mP1, op.mP2, op.mP3); - break; - case PathOp::OP_QUADRATICBEZIERTO: - builder->QuadraticBezierTo(op.mP1, op.mP2); - break; - case PathOp::OP_ARC: - MOZ_ASSERT_UNREACHABLE("Recordings should not contain arc operations"); - break; - case PathOp::OP_CLOSE: - builder->Close(); - break; - } + if (!mPathOps->StreamToSink(*builder)) { + return false; } RefPtr path = builder->Finish(); @@ -2708,54 +2685,24 @@ inline bool RecordedPathCreation::PlayEvent(Translator* aTranslator) const { template void RecordedPathCreation::Record(S& aStream) const { WriteElement(aStream, mRefPtr); - WriteElement(aStream, uint64_t(mPathOps.size())); WriteElement(aStream, mFillRule); - typedef std::vector pathOpVec; - for (pathOpVec::const_iterator iter = mPathOps.begin(); - iter != mPathOps.end(); iter++) { - WriteElement(aStream, iter->mType); - if (sPointCount[iter->mType] >= 1) { - WriteElement(aStream, iter->mP1); - } - if (sPointCount[iter->mType] >= 2) { - WriteElement(aStream, iter->mP2); - } - if (sPointCount[iter->mType] >= 3) { - WriteElement(aStream, iter->mP3); - } - } + mPath->mPathOps.Record(aStream); } template RecordedPathCreation::RecordedPathCreation(S& aStream) : RecordedEventDerived(PATHCREATION) { - uint64_t size; - ReadElement(aStream, mRefPtr); - ReadElement(aStream, size); ReadElement(aStream, mFillRule); - - for (uint64_t i = 0; i < size; i++) { - PathOp newPathOp; - ReadElement(aStream, newPathOp.mType); - if (sPointCount[newPathOp.mType] >= 1) { - ReadElement(aStream, newPathOp.mP1); - } - if (sPointCount[newPathOp.mType] >= 2) { - ReadElement(aStream, newPathOp.mP2); - } - if (sPointCount[newPathOp.mType] >= 3) { - ReadElement(aStream, newPathOp.mP3); - } - - mPathOps.push_back(newPathOp); - } + mPathOps = MakeUnique(aStream); } inline void RecordedPathCreation::OutputSimpleEventInfo( std::stringstream& aStringStream) const { - aStringStream << "[" << mRefPtr - << "] Path created (OpCount: " << mPathOps.size() << ")"; + size_t numberOfOps = + mPath ? mPath->mPathOps.NumberOfOps() : mPathOps->NumberOfOps(); + aStringStream << "[" << mRefPtr << "] Path created (OpCount: " << numberOfOps + << ")"; } inline bool RecordedPathDestruction::PlayEvent(Translator* aTranslator) const { aTranslator->RemovePath(mRefPtr); diff --git a/gfx/2d/RecordingTypes.h b/gfx/2d/RecordingTypes.h index 4558591dec6b..ae1b664fb5ef 100644 --- a/gfx/2d/RecordingTypes.h +++ b/gfx/2d/RecordingTypes.h @@ -8,6 +8,7 @@ #define MOZILLA_GFX_RECORDINGTYPES_H_ #include +#include namespace mozilla { namespace gfx { @@ -27,9 +28,29 @@ void WriteElement(S& aStream, const T& aElement) { ElementStreamFormat::Write(aStream, aElement); } template +void WriteVector(S& aStream, const std::vector& aVector) { + size_t size = aVector.size(); + WriteElement(aStream, size); + if (size) { + aStream.write(reinterpret_cast(aVector.data()), + sizeof(T) * size); + } +} +template void ReadElement(S& aStream, T& aElement) { ElementStreamFormat::Read(aStream, aElement); } +template +void ReadVector(S& aStream, std::vector& aVector) { + size_t size; + ReadElement(aStream, size); + if (size) { + aVector.resize(size); + aStream.read(reinterpret_cast(aVector.data()), sizeof(T) * size); + } else { + aVector.clear(); + } +} } // namespace gfx } // namespace mozilla From c7c1158e8019a77e247adac11f512730bba38555 Mon Sep 17 00:00:00 2001 From: Bob Owen Date: Sun, 2 Dec 2018 14:22:28 +0000 Subject: [PATCH 17/22] Bug 1464032 Part 15: Spread the playback of canvas recordings across multiple threads in the GPU process. r=mattwoodrow --- gfx/2d/2D.h | 12 ++++++ gfx/2d/Factory.cpp | 24 ++++++++++++ gfx/layers/CanvasTranslator.cpp | 7 ++++ gfx/layers/RecordedCanvasEventImpl.h | 4 ++ gfx/layers/ipc/CanvasParent.cpp | 58 ++++++++++++++++++++++------ gfx/layers/ipc/CanvasParent.h | 2 +- 6 files changed, 94 insertions(+), 13 deletions(-) diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h index 98bbf5f55816..3a6387c4f1d2 100644 --- a/gfx/2d/2D.h +++ b/gfx/2d/2D.h @@ -61,6 +61,7 @@ struct ID3D11Texture2D; struct ID3D11Device; struct ID2D1Device; struct ID2D1DeviceContext; +struct ID2D1Multithread; struct IDWriteFactory; struct IDWriteRenderingParams; struct IDWriteFontFace; @@ -1871,6 +1872,17 @@ class GFX2D_API Factory { static DrawEventRecorder* mRecorder; }; +class MOZ_RAII AutoSerializeWithMoz2D final { + public: + explicit AutoSerializeWithMoz2D(BackendType aBackendType); + ~AutoSerializeWithMoz2D(); + + private: +#if defined(WIN32) + RefPtr mMT; +#endif +}; + } // namespace gfx } // namespace mozilla diff --git a/gfx/2d/Factory.cpp b/gfx/2d/Factory.cpp index 3517651e42bd..8aca7ead6bb2 100644 --- a/gfx/2d/Factory.cpp +++ b/gfx/2d/Factory.cpp @@ -738,6 +738,30 @@ FT_Error Factory::LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex, } #endif +AutoSerializeWithMoz2D::AutoSerializeWithMoz2D(BackendType aBackendType) { +#ifdef WIN32 + // We use a multi-threaded ID2D1Factory1, so that makes the calls through the + // Direct2D API thread-safe. However, if the Moz2D objects are using Direct3D + // resources we need to make sure that calls through the Direct3D or DXGI API + // use the Direct2D synchronization. It's possible that this should be pushed + // down into the TextureD3D11 objects, so that we always use this. + if (aBackendType == BackendType::DIRECT2D1_1 || + aBackendType == BackendType::DIRECT2D) { + D2DFactory()->QueryInterface( + static_cast(getter_AddRefs(mMT))); + mMT->Enter(); + } +#endif +} + +AutoSerializeWithMoz2D::~AutoSerializeWithMoz2D() { +#ifdef WIN32 + if (mMT) { + mMT->Leave(); + } +#endif +}; + #ifdef WIN32 already_AddRefed Factory::CreateDrawTargetForD3D11Texture( ID3D11Texture2D* aTexture, SurfaceFormat aFormat) { diff --git a/gfx/layers/CanvasTranslator.cpp b/gfx/layers/CanvasTranslator.cpp index 1bb3a6d997c4..3f1685c365bc 100644 --- a/gfx/layers/CanvasTranslator.cpp +++ b/gfx/layers/CanvasTranslator.cpp @@ -6,6 +6,7 @@ #include "CanvasTranslator.h" +#include "mozilla/gfx/2D.h" #include "mozilla/gfx/Logging.h" #include "RecordedCanvasEventImpl.h" @@ -139,6 +140,8 @@ void CanvasTranslator::BeginTransaction() { mIsInTransaction = true; } void CanvasTranslator::Flush() { #if defined(XP_WIN) + gfx::AutoSerializeWithMoz2D serializeWithMoz2D( + GetReferenceDrawTarget()->GetBackendType()); RefPtr device = gfx::DeviceManagerDx::Get()->GetCanvasDevice(); RefPtr deviceContext; device->GetImmediateContext(getter_AddRefs(deviceContext)); @@ -166,6 +169,8 @@ void CanvasTranslator::AddSurfaceDescriptor(gfx::ReferencePtr aRefPtr, already_AddRefed CanvasTranslator::CreateDrawTarget( gfx::ReferencePtr aRefPtr, const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat) { + gfx::AutoSerializeWithMoz2D serializeWithMoz2D( + GetReferenceDrawTarget()->GetBackendType()); TextureData* textureData = CreateTextureData(mTextureType, aSize, aFormat); textureData->Lock(OpenMode::OPEN_READ_WRITE); mTextureDatas[aRefPtr] = UniquePtr(textureData); @@ -178,6 +183,8 @@ already_AddRefed CanvasTranslator::CreateDrawTarget( void CanvasTranslator::RemoveDrawTarget(gfx::ReferencePtr aDrawTarget) { InlineTranslator::RemoveDrawTarget(aDrawTarget); + gfx::AutoSerializeWithMoz2D serializeWithMoz2D( + GetReferenceDrawTarget()->GetBackendType()); mTextureDatas.erase(aDrawTarget); } diff --git a/gfx/layers/RecordedCanvasEventImpl.h b/gfx/layers/RecordedCanvasEventImpl.h index 7708dd83b8dc..8c49e408fca5 100644 --- a/gfx/layers/RecordedCanvasEventImpl.h +++ b/gfx/layers/RecordedCanvasEventImpl.h @@ -153,6 +153,8 @@ inline bool RecordedTextureLock::PlayCanvasEvent( return false; } + gfx::AutoSerializeWithMoz2D serializeWithMoz2D( + aTranslator->GetReferenceDrawTarget()->GetBackendType()); textureData->Lock(mMode); return true; } @@ -197,6 +199,8 @@ inline bool RecordedTextureUnlock::PlayCanvasEvent( return false; } + gfx::AutoSerializeWithMoz2D serializeWithMoz2D( + aTranslator->GetReferenceDrawTarget()->GetBackendType()); textureData->Unlock(); return true; } diff --git a/gfx/layers/ipc/CanvasParent.cpp b/gfx/layers/ipc/CanvasParent.cpp index 27670d4ddb4a..0baacabb0f8f 100644 --- a/gfx/layers/ipc/CanvasParent.cpp +++ b/gfx/layers/ipc/CanvasParent.cpp @@ -9,6 +9,8 @@ #include "base/thread.h" #include "mozilla/layers/SourceSurfaceSharedData.h" #include "mozilla/layers/TextureClient.h" +#include "mozilla/SharedThreadPool.h" +#include "prsystem.h" #if defined(XP_WIN) # include "mozilla/gfx/DeviceManagerDx.h" @@ -23,9 +25,11 @@ namespace mozilla { namespace layers { static base::Thread* sCanvasThread = nullptr; +static StaticRefPtr sCanvasWorkers; +static bool sShuttingDown = false; static MessageLoop* CanvasPlaybackLoop() { - if (!sCanvasThread) { + if (!sCanvasThread && !sShuttingDown) { MOZ_ASSERT(NS_IsInCompositorThread()); base::Thread* canvasThread = new base::Thread("Canvas"); if (canvasThread->Start()) { @@ -33,7 +37,7 @@ static MessageLoop* CanvasPlaybackLoop() { } } - return sCanvasThread ? sCanvasThread->message_loop() : MessageLoop::current(); + return sCanvasThread ? sCanvasThread->message_loop() : nullptr; } /* static */ @@ -41,6 +45,10 @@ already_AddRefed CanvasParent::Create( ipc::Endpoint&& aEndpoint) { MOZ_ASSERT(NS_IsInCompositorThread()); + if (sShuttingDown) { + return nullptr; + } + RefPtr canvasParent = new CanvasParent(); if (CanvasPlaybackLoop()->IsAcceptingTasks()) { RefPtr runnable = NewRunnableMethod&&>( @@ -52,15 +60,39 @@ already_AddRefed CanvasParent::Create( } /* static */ bool CanvasParent::IsInCanvasThread() { - return sCanvasThread && - sCanvasThread->thread_id() == PlatformThread::CurrentId(); + return (sCanvasWorkers && sCanvasWorkers->IsOnCurrentThread()) || + (sCanvasThread && + sCanvasThread->thread_id() == PlatformThread::CurrentId()); +} + +static already_AddRefed GetCanvasWorkers() { + if (!sCanvasWorkers && !sShuttingDown) { + // Given that the canvas workers are receiving instructions from content + // processes, it probably doesn't make sense to have more than half the + // number of processors doing canvas drawing. We set the lower limit to 2, + // so that even on single processor systems, if there is more than one + // window with canvas drawing, the OS can manage the load between them. + uint32_t threadLimit = std::max(2, PR_GetNumberOfProcessors() / 2); + sCanvasWorkers = + SharedThreadPool::Get(NS_LITERAL_CSTRING("CanvasWorkers"), threadLimit); + } + + return do_AddRef(sCanvasWorkers); } /* static */ void CanvasParent::Shutdown() { + sShuttingDown = true; + if (sCanvasThread) { + sCanvasThread->Stop(); delete sCanvasThread; sCanvasThread = nullptr; } + + if (sCanvasWorkers) { + sCanvasWorkers->Shutdown(); + sCanvasWorkers = nullptr; + } } CanvasParent::CanvasParent() {} @@ -92,23 +124,25 @@ ipc::IPCResult CanvasParent::RecvResumeTranslation() { return IPC_FAIL(this, "Canvas Translation failed."); } - PostStartTranslationTask(); + PostStartTranslationTask(nsIThread::DISPATCH_NORMAL); return IPC_OK(); } -void CanvasParent::PostStartTranslationTask() { - if (MessageLoop::current()->IsAcceptingTasks()) { - RefPtr runnable = - NewRunnableMethod("CanvasParent::StartTranslation", this, - &CanvasParent::StartTranslation); - MessageLoop::current()->PostTask(runnable.forget()); +void CanvasParent::PostStartTranslationTask(uint32_t aDispatchFlags) { + if (sShuttingDown) { + return; } + + RefPtr canvasWorkers = GetCanvasWorkers(); + RefPtr runnable = NewRunnableMethod( + "CanvasParent::StartTranslation", this, &CanvasParent::StartTranslation); + canvasWorkers->Dispatch(runnable.forget(), aDispatchFlags); } void CanvasParent::StartTranslation() { if (!mTranslator->TranslateRecording()) { - PostStartTranslationTask(); + PostStartTranslationTask(nsIThread::DISPATCH_AT_END); } } diff --git a/gfx/layers/ipc/CanvasParent.h b/gfx/layers/ipc/CanvasParent.h index 74b6f8b87396..2fe27d58dbf0 100644 --- a/gfx/layers/ipc/CanvasParent.h +++ b/gfx/layers/ipc/CanvasParent.h @@ -83,7 +83,7 @@ class CanvasParent final : public PCanvasParent { void Bind(Endpoint&& aEndpoint); - void PostStartTranslationTask(); + void PostStartTranslationTask(uint32_t aDispatchFlags); void StartTranslation(); From 47ed611600f6838d5c51c6a23f4cdabd2f2e9555 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Tue, 28 May 2019 12:48:21 +0100 Subject: [PATCH 18/22] Bug 1557434. Split nsPrintObject::Init into separate root-object and nested-object init methods. r=bobowen Differential Revision: https://phabricator.services.mozilla.com/D34006 --HG-- extra : rebase_source : cb246f4b1686d2e7634715b7cea657f762bbca58 extra : amend_source : 3de6ae30fa2156bd38cdea347a77d667c1d65581 --- layout/printing/nsPrintJob.cpp | 9 ++--- layout/printing/nsPrintObject.cpp | 57 ++++++++++++++++++------------- layout/printing/nsPrintObject.h | 9 +++-- 3 files changed, 45 insertions(+), 30 deletions(-) diff --git a/layout/printing/nsPrintJob.cpp b/layout/printing/nsPrintJob.cpp index 1f00c51a4c83..8cdded966bda 100644 --- a/layout/printing/nsPrintJob.cpp +++ b/layout/printing/nsPrintJob.cpp @@ -472,9 +472,9 @@ static void BuildDocTree(BrowsingContext* aBrowsingContext, continue; } auto childPO = MakeUnique(); - childPO->mParent = aPO.get(); - nsresult rv = childPO->Init(childBC->GetDocShell(), window->GetExtantDoc(), - aPO->mPrintPreview); + nsresult rv = childPO->InitAsNestedObject(childBC->GetDocShell(), + window->GetExtantDoc(), + aPO->mPrintPreview, aPO.get()); if (NS_FAILED(rv)) { MOZ_ASSERT_UNREACHABLE("Init failed?"); } @@ -840,7 +840,8 @@ nsresult nsPrintJob::DoCommonPrint(bool aIsPrintPreview, nsAutoScriptBlocker scriptBlocker; printData->mPrintObject = MakeUnique(); - rv = printData->mPrintObject->Init(docShell, aSourceDoc, aIsPrintPreview); + rv = printData->mPrintObject->InitAsRootObject(docShell, aSourceDoc, + aIsPrintPreview); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE( diff --git a/layout/printing/nsPrintObject.cpp b/layout/printing/nsPrintObject.cpp index 899e60d50b50..39f3bd4ae7f0 100644 --- a/layout/printing/nsPrintObject.cpp +++ b/layout/printing/nsPrintObject.cpp @@ -60,16 +60,16 @@ nsPrintObject::~nsPrintObject() { } //------------------------------------------------------------------ -nsresult nsPrintObject::Init(nsIDocShell* aDocShell, Document* aDoc, - bool aPrintPreview) { +nsresult nsPrintObject::InitAsRootObject(nsIDocShell* aDocShell, Document* aDoc, + bool aForPrintPreview) { + NS_ENSURE_STATE(aDocShell); NS_ENSURE_STATE(aDoc); - mPrintPreview = aPrintPreview; - - if (mPrintPreview || mParent) { + if (aForPrintPreview) { mDocShell = aDocShell; } else { - mTreeOwner = do_GetInterface(aDocShell); + // When doing an actual print, we create a BrowsingContext/nsDocShell that + // is detached from any browser window or tab. // Create a new BrowsingContext to create our DocShell in. RefPtr bc = BrowsingContext::Create( @@ -85,31 +85,42 @@ nsresult nsPrintObject::Init(nsIDocShell* aDocShell, Document* aDoc, mDidCreateDocShell = true; MOZ_ASSERT(mDocShell->ItemType() == aDocShell->ItemType()); + + mTreeOwner = do_GetInterface(aDocShell); mDocShell->SetTreeOwner(mTreeOwner); - } - NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); - // Keep the document related to this docshell alive - nsCOMPtr dummy = do_GetInterface(mDocShell); - mozilla::Unused << dummy; - - nsCOMPtr viewer; - mDocShell->GetContentViewer(getter_AddRefs(viewer)); - NS_ENSURE_STATE(viewer); - - if (mParent) { - nsCOMPtr window = aDoc->GetWindow(); - if (window) { - mContent = window->GetFrameElementInternal(); - } - mDocument = aDoc; - return NS_OK; + // Make sure nsDocShell::EnsureContentViewer() is called: + mozilla::Unused << nsDocShell::Cast(mDocShell)->GetDocument(); } mDocument = aDoc->CreateStaticClone(mDocShell); NS_ENSURE_STATE(mDocument); + nsCOMPtr viewer; + mDocShell->GetContentViewer(getter_AddRefs(viewer)); + NS_ENSURE_STATE(viewer); viewer->SetDocument(mDocument); + + mPrintPreview = aForPrintPreview; + + return NS_OK; +} + +nsresult nsPrintObject::InitAsNestedObject(nsIDocShell* aDocShell, + Document* aDoc, + bool aForPrintPreview, + nsPrintObject* aParent) { + NS_ENSURE_STATE(aDocShell); + NS_ENSURE_STATE(aDoc); + + mParent = aParent; + mDocShell = aDocShell; + mDocument = aDoc; + mPrintPreview = aForPrintPreview; + + nsCOMPtr window = aDoc->GetWindow(); + mContent = window->GetFrameElementInternal(); + return NS_OK; } diff --git a/layout/printing/nsPrintObject.h b/layout/printing/nsPrintObject.h index 7411745cf7da..c34eff7e10cb 100644 --- a/layout/printing/nsPrintObject.h +++ b/layout/printing/nsPrintObject.h @@ -33,9 +33,12 @@ class nsPrintObject { nsPrintObject(); ~nsPrintObject(); // non-virtual - // Methods - nsresult Init(nsIDocShell* aDocShell, mozilla::dom::Document* aDoc, - bool aPrintPreview); + nsresult InitAsRootObject(nsIDocShell* aDocShell, + mozilla::dom::Document* aDoc, + bool aForPrintPreview); + nsresult InitAsNestedObject(nsIDocShell* aDocShell, + mozilla::dom::Document* aDoc, + bool aForPrintPreview, nsPrintObject* aParent); bool IsPrintable() { return !mDontPrint; } void DestroyPresentation(); From 197244975116fcf692aa20cd03beaf1a298284e1 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Tue, 28 May 2019 14:16:49 +0100 Subject: [PATCH 19/22] Bug 1557434. Rename nsPrintJob::BuildDocTree to BuildNestedPrintObjects. r=bobowen The previous splitting of nsPrintObject::Init made clear that in fact this method does not create documents at all! This new name better describes what it does. Differential Revision: https://phabricator.services.mozilla.com/D34118 --HG-- extra : rebase_source : 143812a4b5438dff24a7f38b07f0a95660e139ce extra : amend_source : 209937ec2d638bcd60929c6ac3840ee7e0209b73 --- layout/printing/nsPrintJob.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/layout/printing/nsPrintJob.cpp b/layout/printing/nsPrintJob.cpp index 8cdded966bda..f010ed285cfb 100644 --- a/layout/printing/nsPrintJob.cpp +++ b/layout/printing/nsPrintJob.cpp @@ -451,16 +451,12 @@ static void MapContentToWebShells(const UniquePtr& aRootPO, } /** - * Recursively builds the static clone document tree. - * XXXjwatt - uh, CreateStaticClone already takes care of recursively creating - * subdocs (in-process, at least). nsPrintObject::Init creating a static clone - * for subdocs is...broken, surely. * The outparam aDocList returns a (depth first) flat list of all the * nsPrintObjects created. */ -static void BuildDocTree(BrowsingContext* aBrowsingContext, - const UniquePtr& aPO, - nsTArray* aDocList) { +static void BuildNestedPrintObjects(BrowsingContext* aBrowsingContext, + const UniquePtr& aPO, + nsTArray* aDocList) { MOZ_ASSERT(aBrowsingContext, "Pointer is null!"); MOZ_ASSERT(aDocList, "Pointer is null!"); MOZ_ASSERT(aPO, "Pointer is null!"); @@ -480,7 +476,7 @@ static void BuildDocTree(BrowsingContext* aBrowsingContext, } aPO->mKids.AppendElement(std::move(childPO)); aDocList->AppendElement(aPO->mKids.LastElement().get()); - BuildDocTree(childBC, aPO->mKids.LastElement(), aDocList); + BuildNestedPrintObjects(childBC, aPO->mKids.LastElement(), aDocList); } } @@ -852,10 +848,9 @@ nsresult nsPrintJob::DoCommonPrint(bool aIsPrintPreview, printData->mPrintObject->mFrameType = printData->mIsParentAFrameSet ? eFrameSet : eDoc; - // Builds the static clone doc tree and the "tree" of PrintObjects - BuildDocTree(nsDocShell::Cast(printData->mPrintObject->mDocShell) - ->GetBrowsingContext(), - printData->mPrintObject, &printData->mPrintDocList); + BuildNestedPrintObjects(nsDocShell::Cast(printData->mPrintObject->mDocShell) + ->GetBrowsingContext(), + printData->mPrintObject, &printData->mPrintDocList); } // The nsAutoScriptBlocker above will now have been destroyed, which may From 4a0c9a9c7ea2ecc5bf08af706eb90226dda4c2c3 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Tue, 28 May 2019 15:26:59 +0100 Subject: [PATCH 20/22] Bug 1557434. Remove nsPrintObject::mPrintPreview. r=bobowen Differential Revision: https://phabricator.services.mozilla.com/D34134 --HG-- extra : rebase_source : b02b90a21ed16fce0189b0aa317743f01570f57a extra : amend_source : ad608df1346b8ce0bd2ef43305764407008e8e5f --- layout/printing/nsPrintJob.cpp | 5 ++--- layout/printing/nsPrintObject.cpp | 5 ----- layout/printing/nsPrintObject.h | 3 +-- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/layout/printing/nsPrintJob.cpp b/layout/printing/nsPrintJob.cpp index f010ed285cfb..7bc20d71a4d4 100644 --- a/layout/printing/nsPrintJob.cpp +++ b/layout/printing/nsPrintJob.cpp @@ -468,9 +468,8 @@ static void BuildNestedPrintObjects(BrowsingContext* aBrowsingContext, continue; } auto childPO = MakeUnique(); - nsresult rv = childPO->InitAsNestedObject(childBC->GetDocShell(), - window->GetExtantDoc(), - aPO->mPrintPreview, aPO.get()); + nsresult rv = childPO->InitAsNestedObject( + childBC->GetDocShell(), window->GetExtantDoc(), aPO.get()); if (NS_FAILED(rv)) { MOZ_ASSERT_UNREACHABLE("Init failed?"); } diff --git a/layout/printing/nsPrintObject.cpp b/layout/printing/nsPrintObject.cpp index 39f3bd4ae7f0..6c6df39917ca 100644 --- a/layout/printing/nsPrintObject.cpp +++ b/layout/printing/nsPrintObject.cpp @@ -38,7 +38,6 @@ nsPrintObject::nsPrintObject() mDontPrint(true), mPrintAsIs(false), mInvisible(false), - mPrintPreview(false), mDidCreateDocShell(false), mShrinkRatio(1.0), mZoomRatio(1.0) { @@ -101,14 +100,11 @@ nsresult nsPrintObject::InitAsRootObject(nsIDocShell* aDocShell, Document* aDoc, NS_ENSURE_STATE(viewer); viewer->SetDocument(mDocument); - mPrintPreview = aForPrintPreview; - return NS_OK; } nsresult nsPrintObject::InitAsNestedObject(nsIDocShell* aDocShell, Document* aDoc, - bool aForPrintPreview, nsPrintObject* aParent) { NS_ENSURE_STATE(aDocShell); NS_ENSURE_STATE(aDoc); @@ -116,7 +112,6 @@ nsresult nsPrintObject::InitAsNestedObject(nsIDocShell* aDocShell, mParent = aParent; mDocShell = aDocShell; mDocument = aDoc; - mPrintPreview = aForPrintPreview; nsCOMPtr window = aDoc->GetWindow(); mContent = window->GetFrameElementInternal(); diff --git a/layout/printing/nsPrintObject.h b/layout/printing/nsPrintObject.h index c34eff7e10cb..4d5d46517fc1 100644 --- a/layout/printing/nsPrintObject.h +++ b/layout/printing/nsPrintObject.h @@ -38,7 +38,7 @@ class nsPrintObject { bool aForPrintPreview); nsresult InitAsNestedObject(nsIDocShell* aDocShell, mozilla::dom::Document* aDoc, - bool aForPrintPreview, nsPrintObject* aParent); + nsPrintObject* aParent); bool IsPrintable() { return !mDontPrint; } void DestroyPresentation(); @@ -61,7 +61,6 @@ class nsPrintObject { bool mDontPrint; bool mPrintAsIs; bool mInvisible; // Indicates PO is set to not visible by CSS - bool mPrintPreview; bool mDidCreateDocShell; float mShrinkRatio; float mZoomRatio; From 09d6c311f9efec706770fdf78b452563be0bf9b0 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Wed, 29 May 2019 07:14:46 +0100 Subject: [PATCH 21/22] Bug 1557681. Rename nsPrintJob::Cancelled() to Cancel(). r=bobowen "Cancelled" sounds like it's a query and should return a bool. In fact this method sets state in response to a nsIWebBrowserPrint.cancel() being called. Differential Revision: https://phabricator.services.mozilla.com/D34137 --HG-- extra : rebase_source : 97797d906b84ed18a258881a31722179d50943f7 extra : amend_source : c0e1b61f13b2a8ccaec7cc995841948deabbe041 --- layout/base/nsDocumentViewer.cpp | 2 +- layout/printing/nsPrintJob.cpp | 2 +- layout/printing/nsPrintJob.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 5d6954c57fdf..78beeb42b893 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -3750,7 +3750,7 @@ nsDocumentViewer::GetCurrentPrintSettings( NS_IMETHODIMP nsDocumentViewer::Cancel() { NS_ENSURE_TRUE(mPrintJob, NS_ERROR_FAILURE); - return mPrintJob->Cancelled(); + return mPrintJob->Cancel(); } NS_IMETHODIMP diff --git a/layout/printing/nsPrintJob.cpp b/layout/printing/nsPrintJob.cpp index 7bc20d71a4d4..d8b31052658f 100644 --- a/layout/printing/nsPrintJob.cpp +++ b/layout/printing/nsPrintJob.cpp @@ -640,7 +640,7 @@ bool nsPrintJob::CheckBeforeDestroy() { } //------------------------------------------------------- -nsresult nsPrintJob::Cancelled() { +nsresult nsPrintJob::Cancel() { if (mPrt && mPrt->mPrintSettings) { return mPrt->mPrintSettings->SetIsCancelled(true); } diff --git a/layout/printing/nsPrintJob.h b/layout/printing/nsPrintJob.h index 2ef620e74382..e7936e1631b2 100644 --- a/layout/printing/nsPrintJob.h +++ b/layout/printing/nsPrintJob.h @@ -209,7 +209,7 @@ class nsPrintJob final : public nsIObserver, eDocTitleDefault aDefType); bool CheckBeforeDestroy(); - nsresult Cancelled(); + nsresult Cancel(); mozilla::PresShell* GetPrintPreviewPresShell() { return mPrtPreview->mPrintObject->mPresShell; From e3f0977fd5a74d7e7295b16853300d31c257ded1 Mon Sep 17 00:00:00 2001 From: Jan Varga Date: Fri, 7 Jun 2019 15:11:56 +0200 Subject: [PATCH 22/22] Bug 1540401 - Backout Part 1: Convert MOZ_DIAGNOSTIC_ASSERT back to MOZ_ASSERT since bug 1541972 hasn't been fixed yet; r=asuth --- dom/localstorage/ActorsParent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/localstorage/ActorsParent.cpp b/dom/localstorage/ActorsParent.cpp index 4fc7c46d61ba..4075d876e9f7 100644 --- a/dom/localstorage/ActorsParent.cpp +++ b/dom/localstorage/ActorsParent.cpp @@ -8632,7 +8632,7 @@ nsresult QuotaClient::InitOrigin(PersistenceType aPersistenceType, } } - MOZ_DIAGNOSTIC_ASSERT(usage >= 0); + MOZ_ASSERT(usage >= 0); if (!aForGetUsage) { InitUsageForOrigin(aOrigin, usage);