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
This commit is contained in:
sotaro 2019-11-03 10:57:03 +00:00
Родитель 8ad1e883c8
Коммит 34a65d16bb
11 изменённых файлов: 153 добавлений и 17 удалений

Просмотреть файл

@ -37,7 +37,7 @@ class RenderCompositor {
virtual ~RenderCompositor(); virtual ~RenderCompositor();
virtual bool BeginFrame() = 0; virtual bool BeginFrame() = 0;
virtual void EndFrame() = 0; virtual void EndFrame(const FfiVec<DeviceIntRect>& aDirtyRects) = 0;
// Returns false when waiting gpu tasks is failed. // Returns false when waiting gpu tasks is failed.
// It might happen when rendering context is lost. // It might happen when rendering context is lost.
virtual bool WaitForGPU() { return true; } virtual bool WaitForGPU() { return true; }
@ -78,6 +78,10 @@ class RenderCompositor {
virtual void AddSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aPosition, virtual void AddSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aPosition,
wr::DeviceIntRect aClipRect) {} 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 // Whether the surface contents are flipped vertically
virtual bool SurfaceIsYFlipped() { return false; } virtual bool SurfaceIsYFlipped() { return false; }

Просмотреть файл

@ -12,6 +12,7 @@
#include "mozilla/gfx/DeviceManagerDx.h" #include "mozilla/gfx/DeviceManagerDx.h"
#include "mozilla/gfx/gfxVars.h" #include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/Logging.h" #include "mozilla/gfx/Logging.h"
#include "mozilla/gfx/StackArray.h"
#include "mozilla/layers/HelpersD3D11.h" #include "mozilla/layers/HelpersD3D11.h"
#include "mozilla/layers/SyncObject.h" #include "mozilla/layers/SyncObject.h"
#include "mozilla/StaticPrefs_gfx.h" #include "mozilla/StaticPrefs_gfx.h"
@ -55,7 +56,9 @@ RenderCompositorANGLE::RenderCompositorANGLE(
mEGLConfig(nullptr), mEGLConfig(nullptr),
mEGLSurface(nullptr), mEGLSurface(nullptr),
mUseTripleBuffering(false), mUseTripleBuffering(false),
mUseAlpha(false) {} mUseAlpha(false),
mUsePartialPresent(false),
mFullRender(false) {}
RenderCompositorANGLE::~RenderCompositorANGLE() { RenderCompositorANGLE::~RenderCompositorANGLE() {
DestroyEGLSurface(); DestroyEGLSurface();
@ -207,6 +210,7 @@ bool RenderCompositorANGLE::Initialize() {
DXGI_RGBA color = {1.0f, 1.0f, 1.0f, 1.0f}; DXGI_RGBA color = {1.0f, 1.0f, 1.0f, 1.0f};
swapChain1->SetBackgroundColor(&color); swapChain1->SetBackgroundColor(&color);
mSwapChain = swapChain1; mSwapChain = swapChain1;
mSwapChain1 = swapChain1;
mUseTripleBuffering = useTripleBuffering; mUseTripleBuffering = useTripleBuffering;
} }
} }
@ -236,6 +240,13 @@ bool RenderCompositorANGLE::Initialize() {
gfxCriticalNote << "Could not create swap chain: " << gfx::hexa(hr); gfxCriticalNote << "Could not create swap chain: " << gfx::hexa(hr);
return false; return false;
} }
RefPtr<IDXGISwapChain1> 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. // We need this because we don't want DXGI to respond to Alt+Enter.
@ -254,6 +265,8 @@ bool RenderCompositorANGLE::Initialize() {
} }
} }
InitializeUsePartialPresent();
return true; return true;
} }
@ -285,6 +298,7 @@ void RenderCompositorANGLE::CreateSwapChainForDCompIfPossible(
CreateSwapChainForDComp(useTripleBuffering, useAlpha); CreateSwapChainForDComp(useTripleBuffering, useAlpha);
if (swapChain1) { if (swapChain1) {
mSwapChain = swapChain1; mSwapChain = swapChain1;
mSwapChain1 = swapChain1;
mUseTripleBuffering = useTripleBuffering; mUseTripleBuffering = useTripleBuffering;
mUseAlpha = useAlpha; mUseAlpha = useAlpha;
mDCLayerTree->SetDefaultSwapChain(swapChain1); mDCLayerTree->SetDefaultSwapChain(swapChain1);
@ -401,7 +415,7 @@ bool RenderCompositorANGLE::BeginFrame() {
return true; return true;
} }
void RenderCompositorANGLE::EndFrame() { void RenderCompositorANGLE::EndFrame(const FfiVec<DeviceIntRect>& aDirtyRects) {
InsertPresentWaitQuery(); InsertPresentWaitQuery();
if (!UseCompositor()) { if (!UseCompositor()) {
@ -414,7 +428,43 @@ void RenderCompositorANGLE::EndFrame() {
fxrHandler->UpdateOutput(mCtx); 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<RECT, 1> 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(&params);
params.DirtyRectsCount = aDirtyRects.length;
params.pDirtyRects = rects.data();
HRESULT hr;
hr = mSwapChain1->Present1(0, 0, &params);
if (FAILED(hr) && hr != DXGI_STATUS_OCCLUDED) {
gfxCriticalNote << "Present1 failed: " << gfx::hexa(hr);
mFullRender = true;
}
}
} else {
mSwapChain->Present(0, 0);
}
} }
if (mDCLayerTree) { if (mDCLayerTree) {
@ -464,6 +514,9 @@ bool RenderCompositorANGLE::ResizeBufferIfNeeded() {
return false; return false;
} }
if (mUsePartialPresent) {
mFullRender = true;
}
return true; return true;
} }
@ -675,5 +728,24 @@ void RenderCompositorANGLE::AddSurface(wr::NativeSurfaceId aId,
mDCLayerTree->AddSurface(aId, aPosition, aClipRect); 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 wr
} // namespace mozilla } // namespace mozilla

Просмотреть файл

@ -40,7 +40,7 @@ class RenderCompositorANGLE : public RenderCompositor {
bool Initialize(); bool Initialize();
bool BeginFrame() override; bool BeginFrame() override;
void EndFrame() override; void EndFrame(const FfiVec<DeviceIntRect>& aDirtyRects) override;
bool WaitForGPU() override; bool WaitForGPU() override;
void Pause() override; void Pause() override;
bool Resume() override; bool Resume() override;
@ -76,8 +76,13 @@ class RenderCompositorANGLE : public RenderCompositor {
void AddSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aPosition, void AddSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aPosition,
wr::DeviceIntRect aClipRect) override; wr::DeviceIntRect aClipRect) override;
// Interface for partial present
bool RequestFullRender() override;
uint32_t GetMaxPartialPresentRects() override;
protected: protected:
bool UseCompositor(); bool UseCompositor();
void InitializeUsePartialPresent();
void InsertPresentWaitQuery(); void InsertPresentWaitQuery();
bool WaitForPreviousPresentQuery(); bool WaitForPreviousPresentQuery();
bool ResizeBufferIfNeeded(); bool ResizeBufferIfNeeded();
@ -99,6 +104,7 @@ class RenderCompositorANGLE : public RenderCompositor {
RefPtr<ID3D11Device> mDevice; RefPtr<ID3D11Device> mDevice;
RefPtr<ID3D11DeviceContext> mCtx; RefPtr<ID3D11DeviceContext> mCtx;
RefPtr<IDXGISwapChain> mSwapChain; RefPtr<IDXGISwapChain> mSwapChain;
RefPtr<IDXGISwapChain1> mSwapChain1;
UniquePtr<DCLayerTree> mDCLayerTree; UniquePtr<DCLayerTree> mDCLayerTree;
@ -106,6 +112,8 @@ class RenderCompositorANGLE : public RenderCompositor {
RefPtr<ID3D11Query> mRecycledQuery; RefPtr<ID3D11Query> mRecycledQuery;
Maybe<LayoutDeviceIntSize> mBufferSize; Maybe<LayoutDeviceIntSize> mBufferSize;
bool mUsePartialPresent;
bool mFullRender;
}; };
} // namespace wr } // namespace wr

Просмотреть файл

@ -111,7 +111,7 @@ bool RenderCompositorEGL::BeginFrame() {
return true; return true;
} }
void RenderCompositorEGL::EndFrame() { void RenderCompositorEGL::EndFrame(const FfiVec<DeviceIntRect>& aDirtyRects) {
if (mEGLSurface != EGL_NO_SURFACE) { if (mEGLSurface != EGL_NO_SURFACE) {
gl()->SwapBuffers(); gl()->SwapBuffers();
} }

Просмотреть файл

@ -23,7 +23,7 @@ class RenderCompositorEGL : public RenderCompositor {
virtual ~RenderCompositorEGL(); virtual ~RenderCompositorEGL();
bool BeginFrame() override; bool BeginFrame() override;
void EndFrame() override; void EndFrame(const FfiVec<DeviceIntRect>& aDirtyRects) override;
void Pause() override; void Pause() override;
bool Resume() override; bool Resume() override;

Просмотреть файл

@ -91,7 +91,7 @@ bool RenderCompositorOGL::BeginFrame() {
return true; return true;
} }
void RenderCompositorOGL::EndFrame() { void RenderCompositorOGL::EndFrame(const FfiVec<DeviceIntRect>& aDirtyRects) {
InsertFrameDoneSync(); InsertFrameDoneSync();
mGL->SwapBuffers(); mGL->SwapBuffers();

Просмотреть файл

@ -28,7 +28,7 @@ class RenderCompositorOGL : public RenderCompositor {
virtual ~RenderCompositorOGL(); virtual ~RenderCompositorOGL();
bool BeginFrame() override; bool BeginFrame() override;
void EndFrame() override; void EndFrame(const FfiVec<DeviceIntRect>& aDirtyRects) override;
bool WaitForGPU() override; bool WaitForGPU() override;
void Pause() override; void Pause() override;
bool Resume() override; bool Resume() override;

Просмотреть файл

@ -19,6 +19,23 @@
namespace mozilla { namespace mozilla {
namespace wr { 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<DeviceIntRect> 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( wr::WrExternalImage wr_renderer_lock_external_image(
void* aObj, wr::ExternalImageId aId, uint8_t aChannelIndex, void* aObj, wr::ExternalImageId aId, uint8_t aChannelIndex,
wr::ImageRendering aRendering) { wr::ImageRendering aRendering) {
@ -120,10 +137,15 @@ bool RendererOGL::UpdateAndRender(const Maybe<gfx::IntSize>& aReadbackSize,
wr_renderer_update(mRenderer); wr_renderer_update(mRenderer);
if (mCompositor->RequestFullRender()) {
wr_renderer_force_redraw(mRenderer);
}
auto size = mCompositor->GetBufferSize(); auto size = mCompositor->GetBufferSize();
if (!wr_renderer_render(mRenderer, size.width, size.height, aHadSlowFrame, AutoWrRenderResult result(wr_renderer_render(
aOutStats)) { mRenderer, size.width, size.height, aHadSlowFrame, aOutStats));
if (!result.Result()) {
RenderThread::Get()->HandleWebRenderError(WebRenderError::RENDER); RenderThread::Get()->HandleWebRenderError(WebRenderError::RENDER);
mCompositor->GetWidget()->PostRender(&widgetContext); mCompositor->GetWidget()->PostRender(&widgetContext);
return false; return false;
@ -140,7 +162,7 @@ bool RendererOGL::UpdateAndRender(const Maybe<gfx::IntSize>& aReadbackSize,
mScreenshotGrabber.MaybeGrabScreenshot(mRenderer, size.ToUnknownSize()); mScreenshotGrabber.MaybeGrabScreenshot(mRenderer, size.ToUnknownSize());
mCompositor->EndFrame(); mCompositor->EndFrame(result.DirtyRects());
mCompositor->GetWidget()->PostRender(&widgetContext); mCompositor->GetWidget()->PostRender(&widgetContext);

Просмотреть файл

@ -96,7 +96,8 @@ class NewRenderer : public RendererEvent {
&WebRenderMallocEnclosingSizeOf, (uint32_t)wr::RenderRoot::Default, &WebRenderMallocEnclosingSizeOf, (uint32_t)wr::RenderRoot::Default,
compositor->ShouldUseNativeCompositor() ? compositor.get() compositor->ShouldUseNativeCompositor() ? compositor.get()
: nullptr, : nullptr,
mDocHandle, &wrRenderer, mMaxTextureSize)) { compositor->GetMaxPartialPresentRects(), mDocHandle, &wrRenderer,
mMaxTextureSize)) {
// wr_window_new puts a message into gfxCriticalNote if it returns false // wr_window_new puts a message into gfxCriticalNote if it returns false
return; return;
} }

Просмотреть файл

@ -611,19 +611,34 @@ pub extern "C" fn wr_renderer_update(renderer: &mut Renderer) {
renderer.update(); renderer.update();
} }
#[repr(C)]
pub struct WrRenderResult {
result: bool,
dirty_rects: FfiVec<DeviceIntRect>,
}
#[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] #[no_mangle]
pub extern "C" fn wr_renderer_render(renderer: &mut Renderer, pub extern "C" fn wr_renderer_render(renderer: &mut Renderer,
width: i32, width: i32,
height: i32, height: i32,
had_slow_frame: bool, had_slow_frame: bool,
out_stats: &mut RendererStats) -> bool { out_stats: &mut RendererStats) -> WrRenderResult {
if had_slow_frame { if had_slow_frame {
renderer.notify_slow_frame(); renderer.notify_slow_frame();
} }
match renderer.render(DeviceIntSize::new(width, height)) { match renderer.render(DeviceIntSize::new(width, height)) {
Ok(results) => { Ok(results) => {
*out_stats = results.stats; *out_stats = results.stats;
true WrRenderResult {
result: true,
dirty_rects: FfiVec::from_vec(results.dirty_rects),
}
} }
Err(errors) => { Err(errors) => {
for e in 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()); 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] #[no_mangle]
pub extern "C" fn wr_renderer_record_frame( pub extern "C" fn wr_renderer_record_frame(
renderer: &mut Renderer, renderer: &mut Renderer,
@ -1280,6 +1303,7 @@ pub extern "C" fn wr_window_new(window_id: WrWindowId,
enclosing_size_of_op: VoidPtrToSizeFn, enclosing_size_of_op: VoidPtrToSizeFn,
document_id: u32, document_id: u32,
compositor: *mut c_void, compositor: *mut c_void,
max_partial_present_rects: usize,
out_handle: &mut *mut DocumentHandle, out_handle: &mut *mut DocumentHandle,
out_renderer: &mut *mut Renderer, out_renderer: &mut *mut Renderer,
out_max_texture_size: *mut i32) out_max_texture_size: *mut i32)
@ -1339,7 +1363,7 @@ pub extern "C" fn wr_window_new(window_id: WrWindowId,
} }
} else { } else {
CompositorConfig::Draw { CompositorConfig::Draw {
max_partial_present_rects: 0, max_partial_present_rects,
} }
}; };

Просмотреть файл

@ -3607,6 +3607,11 @@
value: false value: false
mirror: once mirror: once
- name: gfx.webrender.max-partial-present-rects
type: uint32_t
value: 0
mirror: once
#ifdef NIGHTLY_BUILD #ifdef NIGHTLY_BUILD
# Keep this pref hidden on non-nightly builds to avoid people accidentally # Keep this pref hidden on non-nightly builds to avoid people accidentally
# turning it on. # turning it on.