From 34a65d16bbb7fb513dd0a51c4b35c7b4347a680b Mon Sep 17 00:00:00 2001 From: sotaro Date: Sun, 3 Nov 2019 10:57:03 +0000 Subject: [PATCH] Bug 1575159 - Implement partial invalidation on Windows r=gw Partial present for WR is off by default. Differential Revision: https://phabricator.services.mozilla.com/D51358 --HG-- extra : moz-landing-system : lando --- gfx/webrender_bindings/RenderCompositor.h | 6 +- .../RenderCompositorANGLE.cpp | 78 ++++++++++++++++++- .../RenderCompositorANGLE.h | 10 ++- .../RenderCompositorEGL.cpp | 2 +- gfx/webrender_bindings/RenderCompositorEGL.h | 2 +- .../RenderCompositorOGL.cpp | 2 +- gfx/webrender_bindings/RenderCompositorOGL.h | 2 +- gfx/webrender_bindings/RendererOGL.cpp | 28 ++++++- gfx/webrender_bindings/WebRenderAPI.cpp | 3 +- gfx/webrender_bindings/src/bindings.rs | 32 +++++++- modules/libpref/init/StaticPrefList.yaml | 5 ++ 11 files changed, 153 insertions(+), 17 deletions(-) diff --git a/gfx/webrender_bindings/RenderCompositor.h b/gfx/webrender_bindings/RenderCompositor.h index 9ed2d13a1a54..a9d9bc4b9fd6 100644 --- a/gfx/webrender_bindings/RenderCompositor.h +++ b/gfx/webrender_bindings/RenderCompositor.h @@ -37,7 +37,7 @@ class RenderCompositor { virtual ~RenderCompositor(); virtual bool BeginFrame() = 0; - virtual void EndFrame() = 0; + virtual void EndFrame(const FfiVec& aDirtyRects) = 0; // Returns false when waiting gpu tasks is failed. // It might happen when rendering context is lost. virtual bool WaitForGPU() { return true; } @@ -78,6 +78,10 @@ class RenderCompositor { virtual void AddSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aPosition, wr::DeviceIntRect aClipRect) {} + // Interface for partial present + virtual bool RequestFullRender() { return false; } + virtual uint32_t GetMaxPartialPresentRects() { return 0; } + // Whether the surface contents are flipped vertically virtual bool SurfaceIsYFlipped() { return false; } diff --git a/gfx/webrender_bindings/RenderCompositorANGLE.cpp b/gfx/webrender_bindings/RenderCompositorANGLE.cpp index 8f74ecfcbce3..05acd60a244a 100644 --- a/gfx/webrender_bindings/RenderCompositorANGLE.cpp +++ b/gfx/webrender_bindings/RenderCompositorANGLE.cpp @@ -12,6 +12,7 @@ #include "mozilla/gfx/DeviceManagerDx.h" #include "mozilla/gfx/gfxVars.h" #include "mozilla/gfx/Logging.h" +#include "mozilla/gfx/StackArray.h" #include "mozilla/layers/HelpersD3D11.h" #include "mozilla/layers/SyncObject.h" #include "mozilla/StaticPrefs_gfx.h" @@ -55,7 +56,9 @@ RenderCompositorANGLE::RenderCompositorANGLE( mEGLConfig(nullptr), mEGLSurface(nullptr), mUseTripleBuffering(false), - mUseAlpha(false) {} + mUseAlpha(false), + mUsePartialPresent(false), + mFullRender(false) {} RenderCompositorANGLE::~RenderCompositorANGLE() { DestroyEGLSurface(); @@ -207,6 +210,7 @@ bool RenderCompositorANGLE::Initialize() { DXGI_RGBA color = {1.0f, 1.0f, 1.0f, 1.0f}; swapChain1->SetBackgroundColor(&color); mSwapChain = swapChain1; + mSwapChain1 = swapChain1; mUseTripleBuffering = useTripleBuffering; } } @@ -236,6 +240,13 @@ bool RenderCompositorANGLE::Initialize() { gfxCriticalNote << "Could not create swap chain: " << gfx::hexa(hr); return false; } + + RefPtr swapChain1; + hr = mSwapChain->QueryInterface( + (IDXGISwapChain1**)getter_AddRefs(swapChain1)); + if (SUCCEEDED(hr)) { + mSwapChain1 = swapChain1; + } } // We need this because we don't want DXGI to respond to Alt+Enter. @@ -254,6 +265,8 @@ bool RenderCompositorANGLE::Initialize() { } } + InitializeUsePartialPresent(); + return true; } @@ -285,6 +298,7 @@ void RenderCompositorANGLE::CreateSwapChainForDCompIfPossible( CreateSwapChainForDComp(useTripleBuffering, useAlpha); if (swapChain1) { mSwapChain = swapChain1; + mSwapChain1 = swapChain1; mUseTripleBuffering = useTripleBuffering; mUseAlpha = useAlpha; mDCLayerTree->SetDefaultSwapChain(swapChain1); @@ -401,7 +415,7 @@ bool RenderCompositorANGLE::BeginFrame() { return true; } -void RenderCompositorANGLE::EndFrame() { +void RenderCompositorANGLE::EndFrame(const FfiVec& aDirtyRects) { InsertPresentWaitQuery(); if (!UseCompositor()) { @@ -414,7 +428,43 @@ void RenderCompositorANGLE::EndFrame() { fxrHandler->UpdateOutput(mCtx); } } - mSwapChain->Present(0, 0); + + const LayoutDeviceIntSize& bufferSize = mBufferSize.ref(); + + if (mUsePartialPresent) { + // Clear full render flag. + mFullRender = false; + // If there is no diry rect, we skip SwapChain present. + if (aDirtyRects.length > 0) { + StackArray rects(aDirtyRects.length); + for (uintptr_t i = 0; i < aDirtyRects.length; i++) { + const DeviceIntRect& rect = aDirtyRects.data[i]; + // Clip rect to bufferSize + rects[i].left = + std::max(0, std::min(rect.origin.x, bufferSize.width)); + rects[i].top = + std::max(0, std::min(rect.origin.y, bufferSize.height)); + rects[i].right = std::max( + 0, std::min(rect.origin.x + rect.size.width, bufferSize.width)); + rects[i].bottom = std::max( + 0, std::min(rect.origin.y + rect.size.height, bufferSize.height)); + } + + DXGI_PRESENT_PARAMETERS params; + PodZero(¶ms); + params.DirtyRectsCount = aDirtyRects.length; + params.pDirtyRects = rects.data(); + + HRESULT hr; + hr = mSwapChain1->Present1(0, 0, ¶ms); + if (FAILED(hr) && hr != DXGI_STATUS_OCCLUDED) { + gfxCriticalNote << "Present1 failed: " << gfx::hexa(hr); + mFullRender = true; + } + } + } else { + mSwapChain->Present(0, 0); + } } if (mDCLayerTree) { @@ -464,6 +514,9 @@ bool RenderCompositorANGLE::ResizeBufferIfNeeded() { return false; } + if (mUsePartialPresent) { + mFullRender = true; + } return true; } @@ -675,5 +728,24 @@ void RenderCompositorANGLE::AddSurface(wr::NativeSurfaceId aId, mDCLayerTree->AddSurface(aId, aPosition, aClipRect); } +void RenderCompositorANGLE::InitializeUsePartialPresent() { + if (UseCompositor() || !mSwapChain1 || + mWidget->AsWindows()->HasFxrOutputHandler() || + StaticPrefs::gfx_webrender_max_partial_present_rects_AtStartup() <= 0) { + mUsePartialPresent = false; + } else { + mUsePartialPresent = true; + } +} + +bool RenderCompositorANGLE::RequestFullRender() { return mFullRender; } + +uint32_t RenderCompositorANGLE::GetMaxPartialPresentRects() { + if (!mUsePartialPresent) { + return 0; + } + return StaticPrefs::gfx_webrender_max_partial_present_rects_AtStartup(); +} + } // namespace wr } // namespace mozilla diff --git a/gfx/webrender_bindings/RenderCompositorANGLE.h b/gfx/webrender_bindings/RenderCompositorANGLE.h index cedc609d9eec..0810adfe5dee 100644 --- a/gfx/webrender_bindings/RenderCompositorANGLE.h +++ b/gfx/webrender_bindings/RenderCompositorANGLE.h @@ -40,7 +40,7 @@ class RenderCompositorANGLE : public RenderCompositor { bool Initialize(); bool BeginFrame() override; - void EndFrame() override; + void EndFrame(const FfiVec& aDirtyRects) override; bool WaitForGPU() override; void Pause() override; bool Resume() override; @@ -76,8 +76,13 @@ class RenderCompositorANGLE : public RenderCompositor { void AddSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aPosition, wr::DeviceIntRect aClipRect) override; + // Interface for partial present + bool RequestFullRender() override; + uint32_t GetMaxPartialPresentRects() override; + protected: bool UseCompositor(); + void InitializeUsePartialPresent(); void InsertPresentWaitQuery(); bool WaitForPreviousPresentQuery(); bool ResizeBufferIfNeeded(); @@ -99,6 +104,7 @@ class RenderCompositorANGLE : public RenderCompositor { RefPtr mDevice; RefPtr mCtx; RefPtr mSwapChain; + RefPtr mSwapChain1; UniquePtr mDCLayerTree; @@ -106,6 +112,8 @@ class RenderCompositorANGLE : public RenderCompositor { RefPtr mRecycledQuery; Maybe mBufferSize; + bool mUsePartialPresent; + bool mFullRender; }; } // namespace wr diff --git a/gfx/webrender_bindings/RenderCompositorEGL.cpp b/gfx/webrender_bindings/RenderCompositorEGL.cpp index e105e115df92..de15a42db731 100644 --- a/gfx/webrender_bindings/RenderCompositorEGL.cpp +++ b/gfx/webrender_bindings/RenderCompositorEGL.cpp @@ -111,7 +111,7 @@ bool RenderCompositorEGL::BeginFrame() { return true; } -void RenderCompositorEGL::EndFrame() { +void RenderCompositorEGL::EndFrame(const FfiVec& aDirtyRects) { if (mEGLSurface != EGL_NO_SURFACE) { gl()->SwapBuffers(); } diff --git a/gfx/webrender_bindings/RenderCompositorEGL.h b/gfx/webrender_bindings/RenderCompositorEGL.h index 6d551c64389c..29df7b96f651 100644 --- a/gfx/webrender_bindings/RenderCompositorEGL.h +++ b/gfx/webrender_bindings/RenderCompositorEGL.h @@ -23,7 +23,7 @@ class RenderCompositorEGL : public RenderCompositor { virtual ~RenderCompositorEGL(); bool BeginFrame() override; - void EndFrame() override; + void EndFrame(const FfiVec& aDirtyRects) override; void Pause() override; bool Resume() override; diff --git a/gfx/webrender_bindings/RenderCompositorOGL.cpp b/gfx/webrender_bindings/RenderCompositorOGL.cpp index 9653f3685831..fba7cf9f6729 100644 --- a/gfx/webrender_bindings/RenderCompositorOGL.cpp +++ b/gfx/webrender_bindings/RenderCompositorOGL.cpp @@ -91,7 +91,7 @@ bool RenderCompositorOGL::BeginFrame() { return true; } -void RenderCompositorOGL::EndFrame() { +void RenderCompositorOGL::EndFrame(const FfiVec& aDirtyRects) { InsertFrameDoneSync(); mGL->SwapBuffers(); diff --git a/gfx/webrender_bindings/RenderCompositorOGL.h b/gfx/webrender_bindings/RenderCompositorOGL.h index d1c303c86407..aea80c1f3263 100644 --- a/gfx/webrender_bindings/RenderCompositorOGL.h +++ b/gfx/webrender_bindings/RenderCompositorOGL.h @@ -28,7 +28,7 @@ class RenderCompositorOGL : public RenderCompositor { virtual ~RenderCompositorOGL(); bool BeginFrame() override; - void EndFrame() override; + void EndFrame(const FfiVec& aDirtyRects) override; bool WaitForGPU() override; void Pause() override; bool Resume() override; diff --git a/gfx/webrender_bindings/RendererOGL.cpp b/gfx/webrender_bindings/RendererOGL.cpp index c6523e1bf2f9..e387f302400c 100644 --- a/gfx/webrender_bindings/RendererOGL.cpp +++ b/gfx/webrender_bindings/RendererOGL.cpp @@ -19,6 +19,23 @@ namespace mozilla { namespace wr { +class MOZ_STACK_CLASS AutoWrRenderResult { + public: + explicit AutoWrRenderResult(WrRenderResult&& aResult) : mResult(aResult) {} + + ~AutoWrRenderResult() { wr_render_result_delete(mResult); } + + bool Result() const { return mResult.result; } + + FfiVec DirtyRects() const { return mResult.dirty_rects; } + + private: + const WrRenderResult mResult; + + AutoWrRenderResult(const AutoWrRenderResult&) = delete; + AutoWrRenderResult& operator=(const AutoWrRenderResult&) = delete; +}; + wr::WrExternalImage wr_renderer_lock_external_image( void* aObj, wr::ExternalImageId aId, uint8_t aChannelIndex, wr::ImageRendering aRendering) { @@ -120,10 +137,15 @@ bool RendererOGL::UpdateAndRender(const Maybe& aReadbackSize, wr_renderer_update(mRenderer); + if (mCompositor->RequestFullRender()) { + wr_renderer_force_redraw(mRenderer); + } + auto size = mCompositor->GetBufferSize(); - if (!wr_renderer_render(mRenderer, size.width, size.height, aHadSlowFrame, - aOutStats)) { + AutoWrRenderResult result(wr_renderer_render( + mRenderer, size.width, size.height, aHadSlowFrame, aOutStats)); + if (!result.Result()) { RenderThread::Get()->HandleWebRenderError(WebRenderError::RENDER); mCompositor->GetWidget()->PostRender(&widgetContext); return false; @@ -140,7 +162,7 @@ bool RendererOGL::UpdateAndRender(const Maybe& aReadbackSize, mScreenshotGrabber.MaybeGrabScreenshot(mRenderer, size.ToUnknownSize()); - mCompositor->EndFrame(); + mCompositor->EndFrame(result.DirtyRects()); mCompositor->GetWidget()->PostRender(&widgetContext); diff --git a/gfx/webrender_bindings/WebRenderAPI.cpp b/gfx/webrender_bindings/WebRenderAPI.cpp index aa0bda03773b..9fbf817c0262 100644 --- a/gfx/webrender_bindings/WebRenderAPI.cpp +++ b/gfx/webrender_bindings/WebRenderAPI.cpp @@ -96,7 +96,8 @@ class NewRenderer : public RendererEvent { &WebRenderMallocEnclosingSizeOf, (uint32_t)wr::RenderRoot::Default, compositor->ShouldUseNativeCompositor() ? compositor.get() : nullptr, - mDocHandle, &wrRenderer, mMaxTextureSize)) { + compositor->GetMaxPartialPresentRects(), mDocHandle, &wrRenderer, + mMaxTextureSize)) { // wr_window_new puts a message into gfxCriticalNote if it returns false return; } diff --git a/gfx/webrender_bindings/src/bindings.rs b/gfx/webrender_bindings/src/bindings.rs index d7fc1566ff3d..ea1edd964004 100644 --- a/gfx/webrender_bindings/src/bindings.rs +++ b/gfx/webrender_bindings/src/bindings.rs @@ -611,19 +611,34 @@ pub extern "C" fn wr_renderer_update(renderer: &mut Renderer) { renderer.update(); } +#[repr(C)] +pub struct WrRenderResult { + result: bool, + dirty_rects: FfiVec, +} + +#[no_mangle] +pub unsafe extern "C" fn wr_render_result_delete(_result: WrRenderResult) { + // _result will be dropped here, and the drop impl on FfiVec will free + // the underlying vec memory +} + #[no_mangle] pub extern "C" fn wr_renderer_render(renderer: &mut Renderer, width: i32, height: i32, had_slow_frame: bool, - out_stats: &mut RendererStats) -> bool { + out_stats: &mut RendererStats) -> WrRenderResult { if had_slow_frame { renderer.notify_slow_frame(); } match renderer.render(DeviceIntSize::new(width, height)) { Ok(results) => { *out_stats = results.stats; - true + WrRenderResult { + result: true, + dirty_rects: FfiVec::from_vec(results.dirty_rects), + } } Err(errors) => { for e in errors { @@ -633,11 +648,19 @@ pub extern "C" fn wr_renderer_render(renderer: &mut Renderer, gfx_critical_note(msg.as_ptr()); } } - false + WrRenderResult { + result: false, + dirty_rects: FfiVec::from_vec(vec![]), + } }, } } +#[no_mangle] +pub extern "C" fn wr_renderer_force_redraw(renderer: &mut Renderer) { + renderer.force_redraw(); +} + #[no_mangle] pub extern "C" fn wr_renderer_record_frame( renderer: &mut Renderer, @@ -1280,6 +1303,7 @@ pub extern "C" fn wr_window_new(window_id: WrWindowId, enclosing_size_of_op: VoidPtrToSizeFn, document_id: u32, compositor: *mut c_void, + max_partial_present_rects: usize, out_handle: &mut *mut DocumentHandle, out_renderer: &mut *mut Renderer, out_max_texture_size: *mut i32) @@ -1339,7 +1363,7 @@ pub extern "C" fn wr_window_new(window_id: WrWindowId, } } else { CompositorConfig::Draw { - max_partial_present_rects: 0, + max_partial_present_rects, } }; diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index c736d6b3dd8c..2694f5677b55 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -3607,6 +3607,11 @@ value: false mirror: once +- name: gfx.webrender.max-partial-present-rects + type: uint32_t + value: 0 + mirror: once + #ifdef NIGHTLY_BUILD # Keep this pref hidden on non-nightly builds to avoid people accidentally # turning it on.