| author | sotaro <sotaro.ikeda.g@gmail.com> |
| Thu, 23 Jan 2020 23:52:05 +0000 | |
| changeset 511591 | 971767c6ed2b2201e172105046ecc61942e03a7e |
| parent 511590 | 436df7dc06c6f82766aa034ed0bcb175b6a95892 |
| child 511592 | af7fe1ccd462c67e6e36ba42e07060f828c407ab |
| push id | 37053 |
| push user | nbeleuzu@mozilla.com |
| push date | Fri, 24 Jan 2020 21:46:30 +0000 |
| treeherder | mozilla-central@6f6e201853c8 [default view] [failures only] |
| perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
| reviewers | gw |
| bugs | 1602643 |
| milestone | 74.0a1 |
| first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
| last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -2495,16 +2495,23 @@ bool CompositorBridgeParent::IsSameProce void CompositorBridgeParent::NotifyWebRenderContextPurge() { MOZ_ASSERT(CompositorLoop() == MessageLoop::current()); RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI(wr::RenderRoot::Default); api->ClearAllCaches(); } +void CompositorBridgeParent::NotifyWebRenderDisableNativeCompositor() { + MOZ_ASSERT(CompositorLoop() == MessageLoop::current()); + if (mWrBridge) { + mWrBridge->DisableNativeCompositor(); + } +} + #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) //#define PLUGINS_LOG(...) printf_stderr("CP [%s]: ", __FUNCTION__); // printf_stderr(__VA_ARGS__); // printf_stderr("\n"); # define PLUGINS_LOG(...) bool CompositorBridgeParent::UpdatePluginWindowState(LayersId aId) { MonitorAutoLock lock(*sIndirectLayerTreesLock);
--- a/gfx/layers/ipc/CompositorBridgeParent.h +++ b/gfx/layers/ipc/CompositorBridgeParent.h @@ -438,16 +438,18 @@ class CompositorBridgeParent final : pub mozilla::ipc::IPCResult RecvInitPCanvasParent( Endpoint<PCanvasParent>&& aEndpoint) final; mozilla::ipc::IPCResult RecvReleasePCanvasParent() final; bool IsSameProcess() const override; void NotifyWebRenderContextPurge(); + void NotifyWebRenderDisableNativeCompositor(); + void NotifyPipelineRendered(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, const VsyncId& aCompositeStartId, TimeStamp& aCompositeStart, TimeStamp& aRenderStart, TimeStamp& aCompositeEnd, wr::RendererStats* aStats = nullptr); void NotifyDidSceneBuild(const nsTArray<wr::RenderRoot>& aRenderRoots, RefPtr<wr::WebRenderPipelineInfo> aInfo);
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp +++ b/gfx/layers/wr/WebRenderBridgeParent.cpp @@ -1729,16 +1729,25 @@ void WebRenderBridgeParent::FlushFramePr // This sends a message to the render backend thread to send a message // to the renderer thread, and waits for that message to be processed. So // this effectively blocks on the render backend and renderer threads, // following the same codepath that WebRender takes to render and composite // a frame. mApis[wr::RenderRoot::Default]->WaitFlushed(); } +void WebRenderBridgeParent::DisableNativeCompositor() { + // Make sure that SceneBuilder thread does not have a task. + mApis[wr::RenderRoot::Default]->FlushSceneBuilder(); + // Disable WebRender's native compositor usage + mApis[wr::RenderRoot::Default]->EnableNativeCompositor(false); + // Ensure we generate and render a frame immediately. + ScheduleForcedGenerateFrame(); +} + void WebRenderBridgeParent::UpdateQualitySettings() { for (auto& api : mApis) { if (!api) { continue; } wr::TransactionBuilder txn; txn.UpdateQualitySettings(gfxVars::AllowSacrificingSubpixelAA()); api->SendTransaction(txn);
--- a/gfx/layers/wr/WebRenderBridgeParent.h +++ b/gfx/layers/wr/WebRenderBridgeParent.h @@ -312,16 +312,18 @@ class WebRenderBridgeParent final * Return the frames collected by the |WebRenderCompositionRecorder| encoded * as data URIs. * * If there is not currently a recorder, this is a no-op and the promise will * be rejected. */ RefPtr<wr::WebRenderAPI::GetCollectedFramesPromise> GetCollectedFrames(); + void DisableNativeCompositor(); + private: class ScheduleSharedSurfaceRelease; explicit WebRenderBridgeParent(const wr::PipelineId& aPipelineId); virtual ~WebRenderBridgeParent(); wr::WebRenderAPI* Api(wr::RenderRoot aRenderRoot) { if (IsRootWebRenderBridgeParent()) {
--- a/gfx/webrender_bindings/DCLayerTree.cpp +++ b/gfx/webrender_bindings/DCLayerTree.cpp @@ -47,19 +47,22 @@ DCLayerTree::DCLayerTree(gl::GLContext* IDCompositionDevice2* aCompositionDevice) : mGL(aGL), mEGLConfig(aEGLConfig), mDevice(aDevice), mCompositionDevice(aCompositionDevice), mDebugCounter(false), mDebugVisualRedrawRegions(false), mEGLImage(EGL_NO_IMAGE), - mColorRBO(0) {} + mColorRBO(0), + mPendingCommit(false) {} -DCLayerTree::~DCLayerTree() { +DCLayerTree::~DCLayerTree() { ReleaseNativeCompositorResources(); } + +void DCLayerTree::ReleaseNativeCompositorResources() { const auto gl = GetGLContext(); DestroyEGLSurface(); // Delete any cached FBO objects for (auto it = mFrameBuffers.begin(); it != mFrameBuffers.end(); ++it) { gl->fDeleteRenderbuffers(1, &it->depthRboId); gl->fDeleteFramebuffers(1, &it->fboId); @@ -115,32 +118,48 @@ DCSurface* DCLayerTree::GetSurface(wr::N } void DCLayerTree::SetDefaultSwapChain(IDXGISwapChain1* aSwapChain) { mRootVisual->AddVisual(mDefaultSwapChainVisual, TRUE, nullptr); mDefaultSwapChainVisual->SetContent(aSwapChain); // Default SwapChain's visual does not need linear interporation. mDefaultSwapChainVisual->SetBitmapInterpolationMode( DCOMPOSITION_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR); - mCompositionDevice->Commit(); + mPendingCommit = true; } void DCLayerTree::MaybeUpdateDebug() { bool updated = false; updated |= MaybeUpdateDebugCounter(); updated |= MaybeUpdateDebugVisualRedrawRegions(); if (updated) { - mCompositionDevice->Commit(); + mPendingCommit = true; } } +void DCLayerTree::MaybeCommit() { + if (!mPendingCommit) { + return; + } + mCompositionDevice->Commit(); +} + void DCLayerTree::WaitForCommitCompletion() { mCompositionDevice->WaitForCommitCompletion(); } +void DCLayerTree::DisableNativeCompositor() { + MOZ_ASSERT(mCurrentSurface.isNothing()); + MOZ_ASSERT(mCurrentLayers.empty()); + + ReleaseNativeCompositorResources(); + mPrevLayers.clear(); + mRootVisual->RemoveAllVisuals(); +} + bool DCLayerTree::MaybeUpdateDebugCounter() { bool debugCounter = StaticPrefs::gfx_webrender_debug_dcomp_counter(); if (mDebugCounter == debugCounter) { return false; } RefPtr<IDCompositionDeviceDebug> debugDevice; HRESULT hr = mCompositionDevice->QueryInterface(
--- a/gfx/webrender_bindings/DCLayerTree.h +++ b/gfx/webrender_bindings/DCLayerTree.h @@ -55,17 +55,19 @@ class DCLayerTree { ID3D11Device* aDevice, HWND aHwnd); explicit DCLayerTree(gl::GLContext* aGL, EGLConfig aEGLConfig, ID3D11Device* aDevice, IDCompositionDevice2* aCompositionDevice); ~DCLayerTree(); void SetDefaultSwapChain(IDXGISwapChain1* aSwapChain); void MaybeUpdateDebug(); + void MaybeCommit(); void WaitForCommitCompletion(); + void DisableNativeCompositor(); // Interface for wr::Compositor void CompositorBeginFrame(); void CompositorEndFrame(); void Bind(wr::NativeTileId aId, wr::DeviceIntPoint* aOffset, uint32_t* aFboId, wr::DeviceIntRect aDirtyRect); void Unbind(); void CreateSurface(wr::NativeSurfaceId aId, wr::DeviceIntSize aTileSize, @@ -91,16 +93,17 @@ class DCLayerTree { bool Initialize(HWND aHwnd); bool MaybeUpdateDebugCounter(); bool MaybeUpdateDebugVisualRedrawRegions(); void DestroyEGLSurface(); GLuint CreateEGLSurfaceForCompositionSurface( wr::DeviceIntRect aDirtyRect, wr::DeviceIntPoint* aOffset, RefPtr<IDCompositionSurface> aCompositionSurface, wr::DeviceIntPoint aSurfaceOffset); + void ReleaseNativeCompositorResources(); RefPtr<gl::GLContext> mGL; EGLConfig mEGLConfig; RefPtr<ID3D11Device> mDevice; RefPtr<IDCompositionDevice2> mCompositionDevice; RefPtr<IDCompositionTarget> mCompositionTarget; @@ -142,16 +145,18 @@ class DCLayerTree { GLuint fboId; GLuint depthRboId; }; // A cache of FBOs, containing a depth buffer allocated to a specific size. // TODO(gw): Might be faster as a hashmap? The length is typically much less // than 10. std::vector<CachedFrameBuffer> mFrameBuffers; + + bool mPendingCommit; }; /** Represents a single picture cache slice. Each surface contains some number of tiles. An implementation may choose to allocate individual tiles to render in to (as the current impl does), or allocate a large single virtual surface to draw into (e.g. the DirectComposition virtual surface API in future).
--- a/gfx/webrender_bindings/RenderCompositor.cpp +++ b/gfx/webrender_bindings/RenderCompositor.cpp @@ -65,16 +65,21 @@ void wr_compositor_destroy_surface(void* compositor->DestroySurface(aId); } void wr_compositor_end_frame(void* aCompositor) { RenderCompositor* compositor = static_cast<RenderCompositor*>(aCompositor); compositor->CompositorEndFrame(); } +void wr_compositor_enable_native_compositor(void* aCompositor, bool aEnable) { + RenderCompositor* compositor = static_cast<RenderCompositor*>(aCompositor); + compositor->EnableNativeCompositor(aEnable); +} + void wr_compositor_unbind(void* aCompositor) { RenderCompositor* compositor = static_cast<RenderCompositor*>(aCompositor); compositor->Unbind(); } /* static */ UniquePtr<RenderCompositor> RenderCompositor::Create( RefPtr<widget::CompositorWidget>&& aWidget) {
--- a/gfx/webrender_bindings/RenderCompositor.h +++ b/gfx/webrender_bindings/RenderCompositor.h @@ -74,32 +74,35 @@ class RenderCompositor { virtual LayoutDeviceIntSize GetBufferSize() = 0; widget::CompositorWidget* GetWidget() const { return mWidget; } layers::SyncObjectHost* GetSyncObject() const { return mSyncObject.get(); } virtual bool IsContextLost(); + virtual bool SupportAsyncScreenshot() { return true; } + virtual bool ShouldUseNativeCompositor() { return false; } virtual uint32_t GetMaxUpdateRects() { return 0; } // Interface for wr::Compositor virtual void CompositorBeginFrame() {} virtual void CompositorEndFrame() {} virtual void Bind(wr::NativeTileId aId, wr::DeviceIntPoint* aOffset, uint32_t* aFboId, wr::DeviceIntRect aDirtyRect) {} virtual void Unbind() {} virtual void CreateSurface(wr::NativeSurfaceId aId, wr::DeviceIntSize aTileSize, bool aIsOpaque) {} virtual void DestroySurface(NativeSurfaceId aId) {} virtual void CreateTile(wr::NativeSurfaceId, int32_t aX, int32_t aY) {} virtual void DestroyTile(wr::NativeSurfaceId, int32_t aX, int32_t aY) {} virtual void AddSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aPosition, wr::DeviceIntRect aClipRect) {} + virtual void EnableNativeCompositor(bool aEnable) {} // Interface for partial present virtual bool UsePartialPresent() { return false; } virtual bool RequestFullRender() { return false; } virtual uint32_t GetMaxPartialPresentRects() { return 0; } // Whether the surface origin is top-left. virtual bool SurfaceOriginIsTopLeft() { return false; }
--- a/gfx/webrender_bindings/RenderCompositorANGLE.cpp +++ b/gfx/webrender_bindings/RenderCompositorANGLE.cpp @@ -58,18 +58,20 @@ UniquePtr<RenderCompositor> RenderCompos RenderCompositorANGLE::RenderCompositorANGLE( RefPtr<widget::CompositorWidget>&& aWidget) : RenderCompositor(std::move(aWidget)), mEGLConfig(nullptr), mEGLSurface(nullptr), mUseTripleBuffering(false), mUseAlpha(false), + mUseNativeCompositor(true), mUsePartialPresent(false), - mFullRender(false) {} + mFullRender(false), + mDisablingNativeCompositor(false) {} RenderCompositorANGLE::~RenderCompositorANGLE() { DestroyEGLSurface(); MOZ_ASSERT(!mEGLSurface); } ID3D11Device* RenderCompositorANGLE::GetDeviceOfEGLDisplay() { auto* egl = gl::GLLibraryEGL::Get(); @@ -491,18 +493,26 @@ RenderedFrameId RenderCompositorANGLE::E mFullRender = true; } } } else { mSwapChain->Present(0, 0); } } + if (mDisablingNativeCompositor) { + // During disabling native compositor, we need to wait all gpu tasks + // complete. Otherwise, rendering window could cause white flash. + WaitForPreviousGraphicsCommandsFinishedQuery(/* aWaitAll */ true); + mDisablingNativeCompositor = false; + } + if (mDCLayerTree) { mDCLayerTree->MaybeUpdateDebug(); + mDCLayerTree->MaybeCommit(); } return frameId; } bool RenderCompositorANGLE::WaitForGPU() { // Note: this waits on the query we inserted in the previous frame, // not the one we just inserted now. Example: @@ -685,18 +695,22 @@ void RenderCompositorANGLE::InsertGraphi if (!query) { return; } mCtx->End(query); mWaitForPresentQueries.emplace(aFrameId, query); } -bool RenderCompositorANGLE::WaitForPreviousGraphicsCommandsFinishedQuery() { +bool RenderCompositorANGLE::WaitForPreviousGraphicsCommandsFinishedQuery( + bool aWaitAll) { size_t waitLatency = mUseTripleBuffering ? 3 : 2; + if (aWaitAll) { + waitLatency = 1; + } while (mWaitForPresentQueries.size() >= waitLatency) { auto queryPair = mWaitForPresentQueries.front(); BOOL result; bool ret = layers::WaitForFrameGPUQuery(mDevice, mCtx, queryPair.second, &result); if (!ret) { @@ -738,22 +752,30 @@ bool RenderCompositorANGLE::IsContextLos // Then this function just uses GetDeviceRemovedReason(). if (mDevice->GetDeviceRemovedReason() != S_OK) { return true; } return false; } bool RenderCompositorANGLE::UseCompositor() { + if (!mUseNativeCompositor) { + return false; + } + if (!mDCLayerTree || !gfx::gfxVars::UseWebRenderCompositor()) { return false; } return true; } +bool RenderCompositorANGLE::SupportAsyncScreenshot() { + return !UseCompositor() && !mDisablingNativeCompositor; +} + bool RenderCompositorANGLE::ShouldUseNativeCompositor() { return UseCompositor(); } uint32_t RenderCompositorANGLE::GetMaxUpdateRects() { if (UseCompositor() && StaticPrefs::gfx_webrender_compositor_max_update_rects_AtStartup() > 0) { return 1; @@ -798,16 +820,52 @@ void RenderCompositorANGLE::DestroyTile( } void RenderCompositorANGLE::AddSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aPosition, wr::DeviceIntRect aClipRect) { mDCLayerTree->AddSurface(aId, aPosition, aClipRect); } +void RenderCompositorANGLE::EnableNativeCompositor(bool aEnable) { + // XXX Re-enable native compositor is not handled yet. + MOZ_RELEASE_ASSERT(!mDisablingNativeCompositor); + MOZ_RELEASE_ASSERT(!aEnable); + + if (!UseCompositor()) { + return; + } + + mUseNativeCompositor = false; + mDCLayerTree->DisableNativeCompositor(); + + bool useAlpha = mWidget->AsWindows()->HasGlass(); + DestroyEGLSurface(); + mBufferSize.reset(); + + RefPtr<IDXGISwapChain1> swapChain1 = + CreateSwapChainForDComp(mUseTripleBuffering, useAlpha); + if (swapChain1) { + mSwapChain = swapChain1; + mUseAlpha = useAlpha; + mDCLayerTree->SetDefaultSwapChain(swapChain1); + // When alpha is used, we want to disable partial present. + // See Bug 1595027. + if (useAlpha) { + mFullRender = true; + } + ResizeBufferIfNeeded(); + } else { + gfxCriticalNote << "Failed to re-create SwapChain"; + RenderThread::Get()->HandleWebRenderError(WebRenderError::NEW_SURFACE); + return; + } + mDisablingNativeCompositor = true; +} + void RenderCompositorANGLE::InitializeUsePartialPresent() { if (UseCompositor() || !mSwapChain1 || mWidget->AsWindows()->HasFxrOutputHandler() || gfx::gfxVars::WebRenderMaxPartialPresentRects() <= 0) { mUsePartialPresent = false; } else { mUsePartialPresent = true; }
--- a/gfx/webrender_bindings/RenderCompositorANGLE.h +++ b/gfx/webrender_bindings/RenderCompositorANGLE.h @@ -59,58 +59,62 @@ class RenderCompositorANGLE : public Ren bool UseTripleBuffering() const override { return mUseTripleBuffering; } LayoutDeviceIntSize GetBufferSize() override; bool IsContextLost() override; bool SurfaceOriginIsTopLeft() override { return true; } + bool SupportAsyncScreenshot() override; + bool ShouldUseNativeCompositor() override; uint32_t GetMaxUpdateRects() override; // Interface for wr::Compositor void CompositorBeginFrame() override; void CompositorEndFrame() override; void Bind(wr::NativeTileId aId, wr::DeviceIntPoint* aOffset, uint32_t* aFboId, wr::DeviceIntRect aDirtyRect) override; void Unbind() override; void CreateSurface(wr::NativeSurfaceId aId, wr::DeviceIntSize aTileSize, bool aIsOpaque) override; void DestroySurface(NativeSurfaceId aId) override; void CreateTile(wr::NativeSurfaceId aId, int32_t aX, int32_t aY) override; void DestroyTile(wr::NativeSurfaceId aId, int32_t aX, int32_t aY) override; void AddSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aPosition, wr::DeviceIntRect aClipRect) override; + void EnableNativeCompositor(bool aEnable) override; // Interface for partial present bool UsePartialPresent() override; bool RequestFullRender() override; uint32_t GetMaxPartialPresentRects() override; bool MaybeReadback(const gfx::IntSize& aReadbackSize, const wr::ImageFormat& aReadbackFormat, const Range<uint8_t>& aReadbackBuffer) override; protected: bool UseCompositor(); void InitializeUsePartialPresent(); void InsertGraphicsCommandsFinishedWaitQuery( RenderedFrameId aRenderedFrameId); - bool WaitForPreviousGraphicsCommandsFinishedQuery(); + bool WaitForPreviousGraphicsCommandsFinishedQuery(bool aWaitAll = false); bool ResizeBufferIfNeeded(); bool CreateEGLSurface(); void DestroyEGLSurface(); ID3D11Device* GetDeviceOfEGLDisplay(); bool CreateSwapChain(); void CreateSwapChainForDCompIfPossible(IDXGIFactory2* aDXGIFactory2); RefPtr<IDXGISwapChain1> CreateSwapChainForDComp(bool aUseTripleBuffering, bool aUseAlpha); bool SutdownEGLLibraryIfNecessary(); RefPtr<ID3D11Query> GetD3D11Query(); + void ReleaseNativeCompositorResources(); EGLConfig mEGLConfig; EGLSurface mEGLSurface; bool mUseTripleBuffering; bool mUseAlpha; RefPtr<ID3D11Device> mDevice; @@ -121,16 +125,19 @@ class RenderCompositorANGLE : public Ren UniquePtr<DCLayerTree> mDCLayerTree; std::queue<std::pair<RenderedFrameId, RefPtr<ID3D11Query>>> mWaitForPresentQueries; RefPtr<ID3D11Query> mRecycledQuery; RenderedFrameId mLastCompletedFrameId; Maybe<LayoutDeviceIntSize> mBufferSize; + bool mUseNativeCompositor; bool mUsePartialPresent; bool mFullRender; + // Used to know a timing of disabling native compositor. + bool mDisablingNativeCompositor; }; } // namespace wr } // namespace mozilla #endif
--- a/gfx/webrender_bindings/RenderThread.cpp +++ b/gfx/webrender_bindings/RenderThread.cpp @@ -488,17 +488,18 @@ void RenderThread::UpdateAndRender( layers::CompositorThreadHolder::Loop()->PostTask( NewRunnableFunction("NotifyDidRenderRunnable", &NotifyDidRender, renderer->GetCompositorBridge(), info, aStartId, aStartTime, start, end, aRender, stats)); if (latestFrameId.IsValid()) { auto recorderIt = mCompositionRecorders.find(aWindowId); - if (recorderIt != mCompositionRecorders.end()) { + if (recorderIt != mCompositionRecorders.end() && + renderer->EnsureAsyncScreenshot()) { recorderIt->second->MaybeRecordFrame(renderer->GetRenderer(), info.get()); } } if (latestFrameId.IsValid()) { // Wait for GPU after posting NotifyDidRender, since the wait is not // necessary for the NotifyDidRender. // The wait is necessary for Textures recycling of AsyncImagePipelineManager
--- a/gfx/webrender_bindings/RendererOGL.cpp +++ b/gfx/webrender_bindings/RendererOGL.cpp @@ -65,17 +65,18 @@ void wr_renderer_unlock_external_image(v RendererOGL::RendererOGL(RefPtr<RenderThread>&& aThread, UniquePtr<RenderCompositor> aCompositor, wr::WindowId aWindowId, wr::Renderer* aRenderer, layers::CompositorBridgeParent* aBridge) : mThread(aThread), mCompositor(std::move(aCompositor)), mRenderer(aRenderer), mBridge(aBridge), - mWindowId(aWindowId) { + mWindowId(aWindowId), + mDisableNativeCompositor(false) { MOZ_ASSERT(mThread); MOZ_ASSERT(mCompositor); MOZ_ASSERT(mRenderer); MOZ_ASSERT(mBridge); MOZ_COUNT_CTOR(RendererOGL); } RendererOGL::~RendererOGL() { @@ -102,16 +103,21 @@ void RendererOGL::Update() { } } static void DoNotifyWebRenderContextPurge( layers::CompositorBridgeParent* aBridge) { aBridge->NotifyWebRenderContextPurge(); } +static void DoWebRenderDisableNativeCompositor( + layers::CompositorBridgeParent* aBridge) { + aBridge->NotifyWebRenderDisableNativeCompositor(); +} + RenderedFrameId RendererOGL::UpdateAndRender( const Maybe<gfx::IntSize>& aReadbackSize, const Maybe<wr::ImageFormat>& aReadbackFormat, const Maybe<Range<uint8_t>>& aReadbackBuffer, bool aHadSlowFrame, RendererStats* aOutStats) { mozilla::widget::WidgetRenderingContext widgetContext; #if defined(XP_MACOSX) @@ -163,40 +169,55 @@ RenderedFrameId RendererOGL::UpdateAndRe aReadbackBuffer.ref())) { wr_renderer_readback(mRenderer, aReadbackSize.ref().width, aReadbackSize.ref().height, aReadbackFormat.ref(), &aReadbackBuffer.ref()[0], aReadbackBuffer.ref().length()); } } - mScreenshotGrabber.MaybeGrabScreenshot(mRenderer, size.ToUnknownSize()); + mScreenshotGrabber.MaybeGrabScreenshot(this, size.ToUnknownSize()); RenderedFrameId frameId = mCompositor->EndFrame(result.DirtyRects()); mCompositor->GetWidget()->PostRender(&widgetContext); #if defined(ENABLE_FRAME_LATENCY_LOG) if (mFrameStartTime) { uint32_t latencyMs = round((TimeStamp::Now() - mFrameStartTime).ToMilliseconds()); printf_stderr("generate frame latencyMs latencyMs %d\n", latencyMs); } // Clear frame start time mFrameStartTime = TimeStamp(); #endif - mScreenshotGrabber.MaybeProcessQueue(mRenderer); + mScreenshotGrabber.MaybeProcessQueue(this); // TODO: Flush pending actions such as texture deletions/unlocks and // textureHosts recycling. return frameId; } +bool RendererOGL::EnsureAsyncScreenshot() { + if (mCompositor->SupportAsyncScreenshot()) { + return true; + } + if (!mDisableNativeCompositor) { + layers::CompositorThreadHolder::Loop()->PostTask( + NewRunnableFunction("DoWebRenderDisableNativeCompositorRunnable", + &DoWebRenderDisableNativeCompositor, mBridge)); + + mDisableNativeCompositor = true; + gfxCriticalNote << "Disable native compositor for async screenshot"; + } + return false; +} + void RendererOGL::CheckGraphicsResetStatus() { if (!mCompositor || !mCompositor->gl()) { return; } gl::GLContext* gl = mCompositor->gl(); if (gl->IsSupported(gl::GLFeature::robustness)) { GLenum resetStatus = gl->fGetGraphicsResetStatus();
--- a/gfx/webrender_bindings/RendererOGL.h +++ b/gfx/webrender_bindings/RendererOGL.h @@ -104,23 +104,27 @@ class RendererOGL { RenderTextureHost* GetRenderTexture(wr::ExternalImageId aExternalImageId); void AccumulateMemoryReport(MemoryReport* aReport); wr::Renderer* GetRenderer() { return mRenderer; } gl::GLContext* gl() const; + bool EnsureAsyncScreenshot(); + protected: RefPtr<RenderThread> mThread; UniquePtr<RenderCompositor> mCompositor; wr::Renderer* mRenderer; layers::CompositorBridgeParent* mBridge; wr::WindowId mWindowId; TimeStamp mFrameStartTime; + bool mDisableNativeCompositor; + RendererScreenshotGrabber mScreenshotGrabber; }; } // namespace wr } // namespace mozilla #endif
--- a/gfx/webrender_bindings/RendererScreenshotGrabber.cpp +++ b/gfx/webrender_bindings/RendererScreenshotGrabber.cpp @@ -11,37 +11,43 @@ using mozilla::layers::ProfilerScreensho namespace mozilla { namespace wr { RendererScreenshotGrabber::RendererScreenshotGrabber() { mMaxScreenshotSize = ProfilerScreenshots::ScreenshotSize(); } void RendererScreenshotGrabber::MaybeGrabScreenshot( - Renderer* aRenderer, const gfx::IntSize& aWindowSize) { - if (ProfilerScreenshots::IsEnabled()) { + RendererOGL* aRendererOGL, const gfx::IntSize& aWindowSize) { + bool isEnabled = + ProfilerScreenshots::IsEnabled() && aRendererOGL->EnsureAsyncScreenshot(); + + if (isEnabled) { if (!mProfilerScreenshots) { mProfilerScreenshots = new ProfilerScreenshots(); } - GrabScreenshot(aRenderer, aWindowSize); + GrabScreenshot(aRendererOGL->GetRenderer(), aWindowSize); } else if (mProfilerScreenshots) { - Destroy(aRenderer); + Destroy(aRendererOGL->GetRenderer()); } } -void RendererScreenshotGrabber::MaybeProcessQueue(Renderer* aRenderer) { - if (ProfilerScreenshots::IsEnabled()) { +void RendererScreenshotGrabber::MaybeProcessQueue(RendererOGL* aRendererOGL) { + bool isEnabled = + ProfilerScreenshots::IsEnabled() && aRendererOGL->EnsureAsyncScreenshot(); + + if (isEnabled) { if (!mProfilerScreenshots) { mProfilerScreenshots = new ProfilerScreenshots(); } - ProcessQueue(aRenderer); + ProcessQueue(aRendererOGL->GetRenderer()); } else if (mProfilerScreenshots) { - Destroy(aRenderer); + Destroy(aRendererOGL->GetRenderer()); } } void RendererScreenshotGrabber::Destroy(Renderer* aRenderer) { mQueue.Clear(); mCurrentFrameQueueItem = Nothing(); mProfilerScreenshots = nullptr;
--- a/gfx/webrender_bindings/RendererScreenshotGrabber.h +++ b/gfx/webrender_bindings/RendererScreenshotGrabber.h @@ -27,24 +27,24 @@ class RendererScreenshotGrabber final { /** * Grab a screenshot from WebRender if we are profiling and screenshots are * enabled. * * The captured screenshot will not be mapped until the second call to * |MaybeProcessQueue| after this call to |MaybeGrabScreenshot|. */ - void MaybeGrabScreenshot(Renderer* aRenderer, + void MaybeGrabScreenshot(RendererOGL* aRendererOGL, const gfx::IntSize& aWindowSize); /** * Process the screenshots pending in the queue if we are profiling and * screenshots are enabled. */ - void MaybeProcessQueue(Renderer* aRenderer); + void MaybeProcessQueue(RendererOGL* aRenderer); private: /** * Drop all our allocated memory when we are no longer profiling. * * This will also instruct WebRender to drop all its Gecko profiler * associated memory. */
--- a/gfx/webrender_bindings/WebRenderAPI.cpp +++ b/gfx/webrender_bindings/WebRenderAPI.cpp @@ -516,16 +516,20 @@ void WebRenderAPI::Readback(const TimeSt task.Wait(); UpdateDebugFlags(gfx::gfxVars::WebRenderDebugFlags()); } void WebRenderAPI::ClearAllCaches() { wr_api_clear_all_caches(mDocHandle); } +void WebRenderAPI::EnableNativeCompositor(bool aEnable) { + wr_api_enable_native_compositor(mDocHandle, aEnable); +} + void WebRenderAPI::Pause() { class PauseEvent : public RendererEvent { public: explicit PauseEvent(layers::SynchronousTask* aTask) : mTask(aTask) { MOZ_COUNT_CTOR(PauseEvent); } virtual ~PauseEvent() { MOZ_COUNT_DTOR(PauseEvent); }
--- a/gfx/webrender_bindings/WebRenderAPI.h +++ b/gfx/webrender_bindings/WebRenderAPI.h @@ -242,16 +242,17 @@ class WebRenderAPI final { void RunOnRenderThread(UniquePtr<RendererEvent> aEvent); void Readback(const TimeStamp& aStartTime, gfx::IntSize aSize, const gfx::SurfaceFormat& aFormat, const Range<uint8_t>& aBuffer); void ClearAllCaches(); + void EnableNativeCompositor(bool aEnable); void Pause(); bool Resume(); void WakeSceneBuilder(); void FlushSceneBuilder(); void NotifyMemoryPressure();
--- a/gfx/webrender_bindings/src/bindings.rs +++ b/gfx/webrender_bindings/src/bindings.rs @@ -1215,16 +1215,20 @@ extern "C" { fn wr_compositor_begin_frame(compositor: *mut c_void); fn wr_compositor_add_surface( compositor: *mut c_void, id: NativeSurfaceId, position: DeviceIntPoint, clip_rect: DeviceIntRect, ); fn wr_compositor_end_frame(compositor: *mut c_void); + fn wr_compositor_enable_native_compositor( + compositor: *mut c_void, + enable: bool, + ); } pub struct WrCompositor(*mut c_void); impl Compositor for WrCompositor { fn create_surface( &mut self, id: NativeSurfaceId, @@ -1340,16 +1344,25 @@ impl Compositor for WrCompositor { fn end_frame(&mut self) { unsafe { wr_compositor_end_frame( self.0, ); } } + + fn enable_native_compositor(&mut self, enable: bool) { + unsafe { + wr_compositor_enable_native_compositor( + self.0, + enable, + ); + } + } } // Call MakeCurrent before this. #[no_mangle] pub extern "C" fn wr_window_new(window_id: WrWindowId, window_width: i32, window_height: i32, @@ -1580,16 +1593,21 @@ pub unsafe extern "C" fn wr_api_accumula *report += dh.api.report_memory(); } #[no_mangle] pub unsafe extern "C" fn wr_api_clear_all_caches(dh: &mut DocumentHandle) { dh.api.send_debug_cmd(DebugCommand::ClearCaches(ClearCache::all())); } +#[no_mangle] +pub unsafe extern "C" fn wr_api_enable_native_compositor(dh: &mut DocumentHandle, enable: bool) { + dh.api.send_debug_cmd(DebugCommand::EnableNativeCompositor(enable)); +} + fn make_transaction(do_async: bool) -> Transaction { let mut transaction = Transaction::new(); // Ensure that we either use async scene building or not based on the // gecko pref, regardless of what the default is. We can remove this once // the scene builder thread is enabled everywhere and working well. if do_async { transaction.use_scene_builder_thread(); } else {
--- a/gfx/wr/tileview/src/main.rs +++ b/gfx/wr/tileview/src/main.rs @@ -21,16 +21,17 @@ pub struct Slice { // invalidation reason CSS colors static CSS_FRACTIONAL_OFFSET: &str = "fill:#4040c0;fill-opacity:0.1;"; static CSS_BACKGROUND_COLOR: &str = "fill:#10c070;fill-opacity:0.1;"; static CSS_SURFACE_OPACITY_CHANNEL: &str = "fill:#c040c0;fill-opacity:0.1;"; static CSS_NO_TEXTURE: &str = "fill:#c04040;fill-opacity:0.1;"; static CSS_NO_SURFACE: &str = "fill:#40c040;fill-opacity:0.1;"; static CSS_PRIM_COUNT: &str = "fill:#40f0f0;fill-opacity:0.1;"; static CSS_CONTENT: &str = "fill:#f04040;fill-opacity:0.1;"; +static CSS_COMPOSITOR_KIND_CHANGED: &str = "fill:#f0c070;fill-opacity:0.1;"; fn tile_node_to_svg(node: &TileNode, x: f32, y: f32) -> String { match &node.kind { TileNodeKind::Leaf { .. } => { format!("<rect x=\"{}\" y=\"{}\" width=\"{}\" height=\"{}\" />\n", (node.rect.origin.x + x) as i32, (node.rect.origin.y + y) as i32, @@ -57,16 +58,17 @@ fn tile_to_svg(key: TileOffset, let tile_fill = match tile.invalidation_reason { Some(InvalidationReason::FractionalOffset) => CSS_FRACTIONAL_OFFSET.to_string(), Some(InvalidationReason::BackgroundColor) => CSS_BACKGROUND_COLOR.to_string(), Some(InvalidationReason::SurfaceOpacityChanged) => CSS_SURFACE_OPACITY_CHANNEL.to_string(), Some(InvalidationReason::NoTexture) => CSS_NO_TEXTURE.to_string(), Some(InvalidationReason::NoSurface) => CSS_NO_SURFACE.to_string(), Some(InvalidationReason::PrimCount) => CSS_PRIM_COUNT.to_string(), + Some(InvalidationReason::CompositorKindChanged) => CSS_COMPOSITOR_KIND_CHANGED.to_string(), Some(InvalidationReason::Content { prim_compare_result } ) => { let _foo = prim_compare_result; CSS_CONTENT.to_string() //TODO do something with the compare result } None => { let mut background = tile.background_color; if background.is_none() { background = slice.tile_cache.background_color
--- a/gfx/wr/webrender/src/composite.rs +++ b/gfx/wr/webrender/src/composite.rs @@ -89,16 +89,29 @@ pub enum CompositorConfig { /// surface update. If this is zero, the entire compositor surface for /// a given tile will be drawn if it's dirty. max_update_rects: usize, /// A client provided interface to a native / OS compositor. compositor: Box<dyn Compositor>, } } +impl CompositorConfig { + pub fn compositor(&mut self) -> Option<&mut Box<dyn Compositor>> { + match self { + CompositorConfig::Native { ref mut compositor, .. } => { + Some(compositor) + } + CompositorConfig::Draw { .. } => { + None + } + } + } +} + impl Default for CompositorConfig { /// Default compositor config is full present without partial present. fn default() -> Self { CompositorConfig::Draw { max_partial_present_rects: 0, } } } @@ -501,16 +514,19 @@ pub trait Compositor { position: DeviceIntPoint, clip_rect: DeviceIntRect, ); /// Commit any changes in the compositor tree for this frame. WR calls /// this once when all surface and visual updates are complete, to signal /// that the OS composite transaction should be applied. fn end_frame(&mut self); + + /// Enable/disable native compositor usage + fn enable_native_compositor(&mut self, enable: bool); } /// Return the total area covered by a set of occluders, accounting for /// overlapping areas between those rectangles. fn area_of_occluders( occluders: &[Occluder], slice: usize, clip_rect: &DeviceIntRect,
--- a/gfx/wr/webrender/src/picture.rs +++ b/gfx/wr/webrender/src/picture.rs @@ -603,16 +603,18 @@ pub enum InvalidationReason { NoSurface, /// The primitive count in the dependency list was different PrimCount, /// The content of one of the primitives was different Content { /// What changed in the primitive that was different prim_compare_result: PrimitiveCompareResult, }, + // The compositor type changed + CompositorKindChanged, } /// A minimal subset of Tile for debug capturing #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct TileSerializer { pub rect: PictureRect, pub current_descriptor: TileDescriptor, @@ -2095,16 +2097,46 @@ impl TileCacheInstance { // simple composite mode, the texture cache handle will expire and be collected // by the texture cache. For native compositor mode, we need to explicitly // invoke a callback to the client to destroy that surface. frame_state.composite_state.destroy_native_tiles( self.old_tiles.values_mut(), frame_state.resource_cache, ); + // If compositor mode is changed, need to drop all incompatible tiles. + match (frame_context.config.compositor_kind, self.native_surface_id) { + (CompositorKind::Draw { .. }, Some(_)) => { + frame_state.composite_state.destroy_native_tiles( + self.tiles.values_mut(), + frame_state.resource_cache, + ); + for tile in self.tiles.values_mut() { + tile.surface = None; + // Invalidate the entire tile to force a redraw. + tile.invalidate(None, InvalidationReason::CompositorKindChanged); + } + if let Some(native_surface_id) = self.native_surface_id.take() { + frame_state.resource_cache.destroy_compositor_surface(native_surface_id); + } + } + (CompositorKind::Native { .. }, None) => { + // This could hit even when compositor mode is not changed, + // then we need to check if there are incompatible tiles. + for tile in self.tiles.values_mut() { + if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::TextureCache { .. }, .. }) = tile.surface { + tile.surface = None; + // Invalidate the entire tile to force a redraw. + tile.invalidate(None, InvalidationReason::CompositorKindChanged); + } + } + } + (_, _) => {} + } + world_culling_rect } /// Update the dependencies for each tile for a given primitive instance. pub fn update_prim_dependencies( &mut self, prim_instance: &PrimitiveInstance, prim_spatial_node_index: SpatialNodeIndex,
--- a/gfx/wr/webrender/src/render_backend.rs +++ b/gfx/wr/webrender/src/render_backend.rs @@ -706,16 +706,17 @@ pub struct RenderBackend { payload_buffer: Vec<Payload>, default_device_pixel_ratio: f32, gpu_cache: GpuCache, resource_cache: ResourceCache, frame_config: FrameBuilderConfig, + default_compositor_kind: CompositorKind, documents: FastHashMap<DocumentId, Document>, notifier: Box<dyn RenderNotifier>, recorder: Option<Box<dyn ApiRecordingReceiver>>, logrecorder: Option<Box<LogRecorder>>, tile_cache_logger: TileCacheLogger, sampler: Option<Box<dyn AsyncPropertySampler + Send>>, size_of_ops: Option<MallocSizeOfOps>, @@ -750,16 +751,17 @@ impl RenderBackend { scene_tx, low_priority_scene_tx, scene_rx, payload_buffer: Vec::new(), default_device_pixel_ratio, resource_cache, gpu_cache: GpuCache::new(), frame_config, + default_compositor_kind : frame_config.compositor_kind, documents: FastHashMap::default(), notifier, recorder, logrecorder: None, tile_cache_logger: TileCacheLogger::new(500usize), sampler, size_of_ops, debug_flags, @@ -1220,16 +1222,43 @@ impl RenderBackend { }; return RenderBackendStatus::Continue; } DebugCommand::ClearCaches(mask) => { self.resource_cache.clear(mask); return RenderBackendStatus::Continue; } + DebugCommand::EnableNativeCompositor(enable) => { + // Default CompositorKind should be Native + if let CompositorKind::Draw { .. } = self.default_compositor_kind { + unreachable!(); + } + + let compositor_kind = if enable { + self.default_compositor_kind + } else { + CompositorKind::default() + }; + + for (_, doc) in &mut self.documents { + doc.scene.config.compositor_kind = compositor_kind; + doc.frame_is_valid = false; + } + + self.frame_config.compositor_kind = compositor_kind; + + // Update config in SceneBuilder + self.low_priority_scene_tx.send(SceneBuilderRequest::SetFrameBuilderConfig( + self.frame_config.clone() + )).unwrap(); + + // We don't want to forward this message to the renderer. + return RenderBackendStatus::Continue; + } DebugCommand::SimulateLongSceneBuild(time_ms) => { self.scene_tx.send(SceneBuilderRequest::SimulateLongSceneBuild(time_ms)).unwrap(); return RenderBackendStatus::Continue; } DebugCommand::SimulateLongLowPrioritySceneBuild(time_ms) => { self.low_priority_scene_tx.send( SceneBuilderRequest::SimulateLongLowPrioritySceneBuild(time_ms) ).unwrap(); @@ -1509,17 +1538,17 @@ impl RenderBackend { let build_frame = (render_frame && !doc.frame_is_valid && doc.has_pixels()) || (requires_frame_build && doc.can_render()); // Request composite is true when we want to composite frame even when // there is no frame update. This happens when video frame is updated under // external image with NativeTexture or when platform requested to composite frame. if invalidate_rendered_frame { doc.rendered_frame_is_valid = false; - if let CompositorKind::Draw { max_partial_present_rects } = self.frame_config.compositor_kind { + if let CompositorKind::Draw { max_partial_present_rects } = doc.scene.config.compositor_kind { // When partial present is enabled, we need to force redraw. if max_partial_present_rects > 0 { let msg = ResultMsg::ForceRedraw; self.result_tx.send(msg).unwrap(); } } }
--- a/gfx/wr/webrender/src/renderer.rs +++ b/gfx/wr/webrender/src/renderer.rs @@ -1891,16 +1891,18 @@ pub struct Renderer { #[cfg(feature = "capture")] read_fbo: FBOId, #[cfg(feature = "replay")] owned_external_images: FastHashMap<(ExternalImageId, u8), ExternalTexture>, /// The compositing config, affecting how WR composites into the final scene. compositor_config: CompositorConfig, + current_compositor_kind: CompositorKind, + /// Maintains a set of allocated native composite surfaces. This allows any /// currently allocated surfaces to be cleaned up as soon as deinit() is /// called (the normal bookkeeping for native surfaces exists in the /// render backend thread). allocated_native_surfaces: FastHashSet<NativeSurfaceId>, /// If true, partial present state has been reset and everything needs to /// be drawn on the next render. @@ -2418,16 +2420,17 @@ impl Renderer { notifications: Vec::new(), device_size: None, zoom_debug_texture: None, cursor_position: DeviceIntPoint::zero(), shared_texture_cache_cleared: false, documents_seen: FastHashSet::default(), force_redraw: true, compositor_config: options.compositor_config, + current_compositor_kind: compositor_kind, allocated_native_surfaces: FastHashSet::default(), debug_overlay_state: DebugOverlayState::new(), }; // We initially set the flags to default and then now call set_debug_flags // to ensure any potential transition when enabling a flag is run. renderer.set_debug_flags(debug_flags); @@ -2865,17 +2868,18 @@ impl Renderer { self.debug_server.send(json); } DebugCommand::SaveCapture(..) | DebugCommand::LoadCapture(..) => { panic!("Capture commands are not welcome here! Did you build with 'capture' feature?") } DebugCommand::ClearCaches(_) | DebugCommand::SimulateLongSceneBuild(_) - | DebugCommand::SimulateLongLowPrioritySceneBuild(_) => {} + | DebugCommand::SimulateLongLowPrioritySceneBuild(_) + | DebugCommand::EnableNativeCompositor(_) => {} DebugCommand::InvalidateGpuCache => { match self.gpu_cache_texture.bus { GpuCacheBus::PixelBuffer { ref mut rows, .. } => { info!("Invalidating GPU caches"); for row in rows { row.is_dirty = true; } } @@ -2956,17 +2960,19 @@ impl Renderer { DebugFlags::GPU_CACHE_DBG | DebugFlags::SLOW_FRAME_INDICATOR | DebugFlags::PICTURE_CACHING_DBG | DebugFlags::PRIMITIVE_DBG | DebugFlags::ZOOM_DBG ); // Update the debug overlay surface, if we are running in native compositor mode. - if let CompositorConfig::Native { ref mut compositor, .. } = self.compositor_config { + if let CompositorKind::Native { .. } = self.current_compositor_kind { + let compositor = self.compositor_config.compositor().unwrap(); + // If there is a current surface, destroy it if we don't need it for this frame, or if // the size has changed. if let Some(current_size) = self.debug_overlay_state.current_size { if !self.debug_overlay_state.is_enabled || current_size != framebuffer_size { compositor.destroy_surface(NativeSurfaceId::DEBUG_OVERLAY); self.debug_overlay_state.current_size = None; } } @@ -2985,17 +2991,18 @@ impl Renderer { } } } /// Bind a draw target for the debug / profiler overlays, if required. fn bind_debug_overlay(&mut self) { // Debug overlay setup are only required in native compositing mode if self.debug_overlay_state.is_enabled { - if let CompositorConfig::Native { ref mut compositor, .. } = self.compositor_config { + if let CompositorKind::Native { .. } = self.current_compositor_kind { + let compositor = self.compositor_config.compositor().unwrap(); let surface_size = self.debug_overlay_state.current_size.unwrap(); // Bind the native surface let surface_info = compositor.bind( NativeTileId::DEBUG_OVERLAY, DeviceIntRect::new( DeviceIntPoint::zero(), surface_size, @@ -3019,17 +3026,18 @@ impl Renderer { } } } /// Unbind the draw target for debug / profiler overlays, if required. fn unbind_debug_overlay(&mut self) { // Debug overlay setup are only required in native compositing mode if self.debug_overlay_state.is_enabled { - if let CompositorConfig::Native { ref mut compositor, .. } = self.compositor_config { + if let CompositorKind::Native { .. } = self.current_compositor_kind { + let compositor = self.compositor_config.compositor().unwrap(); // Unbind the draw target and add it to the visual tree to be composited compositor.unbind(); compositor.add_surface( NativeSurfaceId::DEBUG_OVERLAY, DeviceIntPoint::zero(), DeviceIntRect::new( DeviceIntPoint::zero(), @@ -3050,16 +3058,45 @@ impl Renderer { ) -> Result<RenderResults, Vec<RendererError>> { profile_scope!("render"); let mut results = RenderResults::default(); if self.active_documents.is_empty() { self.last_time = precise_time_ns(); return Ok(results); } + let compositor_kind = self.active_documents[0].1.frame.composite_state.compositor_kind; + // CompositorKind is updated + if self.current_compositor_kind != compositor_kind { + let enable = match (self.current_compositor_kind, compositor_kind) { + (CompositorKind::Native { .. }, CompositorKind::Draw { .. }) => { + if self.debug_overlay_state.current_size.is_some() { + self.compositor_config + .compositor() + .unwrap() + .destroy_surface(NativeSurfaceId::DEBUG_OVERLAY); + self.debug_overlay_state.current_size = None; + } + false + } + (CompositorKind::Draw { .. }, CompositorKind::Native { .. }) => { + true + } + (_, _) => { + unreachable!(); + } + }; + + self.compositor_config + .compositor() + .unwrap() + .enable_native_compositor(enable); + self.current_compositor_kind = compositor_kind; + } + let mut frame_profiles = Vec::new(); let mut profile_timers = RendererProfileTimers::new(); // The texture resolver scope should be outside of any rendering, including // debug rendering. This ensures that when we return render targets to the // pool via glInvalidateFramebuffer, we don't do any debug rendering after // that point. Otherwise, the bind / invalidate / bind logic trips up the // render pass logic in tiled / mobile GPUs, resulting in an extra copy / @@ -3098,33 +3135,36 @@ impl Renderer { self.update_native_surfaces(); frame_id }); // Inform the client that we are starting a composition transaction if native // compositing is enabled. This needs to be done early in the frame, so that // we can create debug overlays after drawing the main surfaces. - if let CompositorConfig::Native { ref mut compositor, .. } = self.compositor_config { + if let CompositorKind::Native { .. } = self.current_compositor_kind { + let compositor = self.compositor_config.compositor().unwrap(); compositor.begin_frame(); } profile_timers.cpu_time.profile(|| { //Note: another borrowck dance let mut active_documents = mem::replace(&mut self.active_documents, Vec::default()); // sort by the document layer id active_documents.sort_by_key(|&(_, ref render_doc)| render_doc.frame.layer); #[cfg(feature = "replay")] self.texture_resolver.external_images.extend( self.owned_external_images.iter().map(|(key, value)| (*key, value.clone())) ); let last_document_index = active_documents.len() - 1; for (doc_index, (document_id, RenderedDocument { ref mut frame, .. })) in active_documents.iter_mut().enumerate() { + assert!(self.current_compositor_kind == frame.composite_state.compositor_kind); + if self.shared_texture_cache_cleared { assert!(self.documents_seen.contains(&document_id), "Cleared texture cache without sending new document frame."); } frame.profile_counters.reset_targets(); self.prepare_gpu_cache(frame); assert!(frame.gpu_cache_frame_id <= self.gpu_cache_frame_id, @@ -3275,19 +3315,19 @@ impl Renderer { self.gpu_cache_upload_time = 0; profile_timers.cpu_time.profile(|| { if let Some(debug_renderer) = self.debug.try_get_mut() { let small_screen = self.debug_flags.contains(DebugFlags::SMALL_SCREEN); let scale = if small_screen { 1.6 } else { 1.0 }; // TODO(gw): Tidy this up so that compositor config integrates better // with the (non-compositor) surface y-flip options. - let surface_origin_is_top_left = match self.compositor_config { - CompositorConfig::Native { .. } => true, - CompositorConfig::Draw { .. } => self.device.surface_origin_is_top_left(), + let surface_origin_is_top_left = match self.current_compositor_kind { + CompositorKind::Native { .. } => true, + CompositorKind::Draw { .. } => self.device.surface_origin_is_top_left(), }; debug_renderer.render( &mut self.device, device_size, scale, surface_origin_is_top_left, ); } @@ -3306,17 +3346,18 @@ impl Renderer { // Unbind the target for the debug overlay. No debug or profiler drawing // can occur afer this point. self.unbind_debug_overlay(); } // Inform the client that we are finished this composition transaction if native // compositing is enabled. This must be called after any debug / profiling compositor // surfaces have been drawn and added to the visual tree. - if let CompositorConfig::Native { ref mut compositor, .. } = self.compositor_config { + if let CompositorKind::Native { .. } = self.current_compositor_kind { + let compositor = self.compositor_config.compositor().unwrap(); compositor.end_frame(); } self.documents_seen.clear(); self.shared_texture_cache_cleared = false; if self.renderer_errors.is_empty() { Ok(results) @@ -5209,21 +5250,22 @@ impl Renderer { }; // Picture caching can be enabled / disabled dynamically from frame to // frame. This is determined by what the frame builder selected, and is // passed to the renderer via the composite state. if frame.composite_state.picture_caching_is_enabled { // If we have a native OS compositor, then make use of that interface // to specify how to composite each of the picture cache surfaces. - match self.compositor_config { - CompositorConfig::Native { ref mut compositor, .. } => { + match self.current_compositor_kind { + CompositorKind::Native { .. } => { + let compositor = self.compositor_config.compositor().unwrap(); frame.composite_state.composite_native(&mut **compositor); } - CompositorConfig::Draw { max_partial_present_rects, .. } => { + CompositorKind::Draw { max_partial_present_rects, .. } => { self.composite_simple( &frame.composite_state, clear_framebuffer, draw_target, &projection, results, max_partial_present_rects, ); @@ -5292,21 +5334,22 @@ impl Renderer { DrawTarget::from_texture( texture, layer as usize, true, ) } ResolvedSurfaceTexture::Native { id, size } => { - let surface_info = match self.compositor_config { - CompositorConfig::Native { ref mut compositor, .. } => { + let surface_info = match self.current_compositor_kind { + CompositorKind::Native { .. } => { + let compositor = self.compositor_config.compositor().unwrap(); compositor.bind(id, picture_target.dirty_rect) } - CompositorConfig::Draw { .. } => { + CompositorKind::Draw { .. } => { unreachable!(); } }; DrawTarget::NativeSurface { offset: surface_info.origin, external_fbo_id: surface_info.fbo_id, dimensions: size, @@ -5329,21 +5372,22 @@ impl Renderer { frame.content_origin, &projection, &frame.render_tasks, &mut results.stats, ); // Native OS surfaces must be unbound at the end of drawing to them if let ResolvedSurfaceTexture::Native { .. } = picture_target.surface { - match self.compositor_config { - CompositorConfig::Native { ref mut compositor, .. } => { + match self.current_compositor_kind { + CompositorKind::Native { .. } => { + let compositor = self.compositor_config.compositor().unwrap(); compositor.unbind(); } - CompositorConfig::Draw { .. } => { + CompositorKind::Draw { .. } => { unreachable!(); } } } } } for (target_index, target) in alpha.targets.iter().enumerate() {
--- a/gfx/wr/webrender_api/src/api.rs +++ b/gfx/wr/webrender_api/src/api.rs @@ -962,16 +962,18 @@ pub enum DebugCommand { /// Fetch screenshot. FetchScreenshot, /// Save a capture of all the documents state. SaveCapture(PathBuf, CaptureBits), /// Load a capture of all the documents state. LoadCapture(PathBuf, MsgSender<CapturedDocument>), /// Clear cached resources, forcing them to be re-uploaded from templates. ClearCaches(ClearCache), + /// Enable/disable native compositor usage + EnableNativeCompositor(bool), /// Invalidate GPU cache, forcing the update from the CPU mirror. InvalidateGpuCache, /// Causes the scene builder to pause for a given amount of milliseconds each time it /// processes a transaction. SimulateLongSceneBuild(u32), /// Causes the low priority scene builder to pause for a given amount of milliseconds /// each time it processes a transaction. SimulateLongLowPrioritySceneBuild(u32),