Bug 1656818 - Move decision to flip WebRender readback closer to the source, and make it correct for SWGL. r=lsalzman,geckoview-reviewers,snorp

Differential Revision: https://phabricator.services.mozilla.com/D86892
This commit is contained in:
Matt Woodrow 2020-08-14 18:40:09 +00:00
parent 02b6ed52b4
commit a250b4d7a3
23 changed files with 81 additions and 50 deletions

View File

@ -1450,7 +1450,7 @@ void LayerManagerComposite::HandlePixelsTarget() {
gl->fReadPixels(0, 0, bufferWidth, bufferHeight, LOCAL_GL_RGBA,
LOCAL_GL_UNSIGNED_BYTE, mem.get<uint8_t>());
Unused << mScreenPixelsTarget->SendScreenPixels(
std::move(mem), ScreenIntSize(bufferWidth, bufferHeight));
std::move(mem), ScreenIntSize(bufferWidth, bufferHeight), true);
mScreenPixelsTarget = nullptr;
}
#endif

View File

@ -39,7 +39,7 @@ parent:
child:
async ToolbarAnimatorMessageFromCompositor(int32_t aMessage);
async RootFrameMetrics(ScreenPoint aScrollOffset, CSSToScreenScale aZoom);
async ScreenPixels(Shmem aMem, ScreenIntSize aSize);
async ScreenPixels(Shmem aMem, ScreenIntSize aSize, bool aNeedsYFlip);
};
} // layers

View File

@ -64,7 +64,7 @@ parent:
async UpdateResources(OpUpdateResource[] aResourceUpdates,
RefCountedShmem[] aSmallShmems, Shmem[] aLargeShmems);
async ParentCommands(WebRenderParentCommand[] commands);
sync GetSnapshot(PTexture texture);
sync GetSnapshot(PTexture texture) returns (bool aNeedsYFlip);
async SetLayersObserverEpoch(LayersObserverEpoch childEpoch);
async ClearCachedResources();
// Invalidate rendered frame

View File

@ -240,10 +240,10 @@ mozilla::ipc::IPCResult UiCompositorControllerChild::RecvRootFrameMetrics(
}
mozilla::ipc::IPCResult UiCompositorControllerChild::RecvScreenPixels(
ipc::Shmem&& aMem, const ScreenIntSize& aSize) {
ipc::Shmem&& aMem, const ScreenIntSize& aSize, bool aNeedsYFlip) {
#if defined(MOZ_WIDGET_ANDROID)
if (mWidget) {
mWidget->RecvScreenPixels(std::move(aMem), aSize);
mWidget->RecvScreenPixels(std::move(aMem), aSize, aNeedsYFlip);
}
#endif // defined(MOZ_WIDGET_ANDROID)

View File

@ -60,7 +60,8 @@ class UiCompositorControllerChild final
mozilla::ipc::IPCResult RecvRootFrameMetrics(const ScreenPoint& aScrollOffset,
const CSSToScreenScale& aZoom);
mozilla::ipc::IPCResult RecvScreenPixels(Shmem&& aMem,
const ScreenIntSize& aSize);
const ScreenIntSize& aSize,
bool aNeedsYFlip);
private:
explicit UiCompositorControllerChild(const uint64_t& aProcessToken);

View File

@ -1528,18 +1528,21 @@ void WebRenderBridgeParent::MaybeCaptureScreenPixels() {
IntSize size(client_size.width, client_size.height);
bool needsYFlip = false;
mApi->Readback(TimeStamp::Now(), size, format,
Range<uint8_t>(mem.get<uint8_t>(), buffer_size));
Range<uint8_t>(mem.get<uint8_t>(), buffer_size), &needsYFlip);
Unused << mScreenPixelsTarget->SendScreenPixels(
std::move(mem), ScreenIntSize(client_size.width, client_size.height));
std::move(mem), ScreenIntSize(client_size.width, client_size.height),
needsYFlip);
mScreenPixelsTarget = nullptr;
}
#endif
mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetSnapshot(
PTextureParent* aTexture) {
PTextureParent* aTexture, bool* aNeedsYFlip) {
*aNeedsYFlip = false;
if (mDestroyed) {
return IPC_OK();
}
@ -1591,7 +1594,7 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetSnapshot(
FlushSceneBuilds();
FlushFrameGeneration();
mApi->Readback(start, size, bufferTexture->GetFormat(),
Range<uint8_t>(buffer, buffer_size));
Range<uint8_t>(buffer, buffer_size), aNeedsYFlip);
return IPC_OK();
}

View File

@ -170,7 +170,8 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
const FocusTarget& aFocusTarget) override;
mozilla::ipc::IPCResult RecvParentCommands(
nsTArray<WebRenderParentCommand>&& commands) override;
mozilla::ipc::IPCResult RecvGetSnapshot(PTextureParent* aTexture) override;
mozilla::ipc::IPCResult RecvGetSnapshot(PTextureParent* aTexture,
bool* aNeedsYFlip) override;
mozilla::ipc::IPCResult RecvSetLayersObserverEpoch(
const LayersObserverEpoch& aChildEpoch) override;

View File

@ -471,7 +471,8 @@ void WebRenderLayerManager::MakeSnapshotIfRequired(LayoutDeviceIntSize aSize) {
}
IntRect bounds = ToOutsideIntRect(mTarget->GetClipExtents());
if (!WrBridge()->SendGetSnapshot(texture->GetIPDLActor())) {
bool needsYFlip = false;
if (!WrBridge()->SendGetSnapshot(texture->GetIPDLActor(), &needsYFlip)) {
return;
}
@ -495,14 +496,6 @@ void WebRenderLayerManager::MakeSnapshotIfRequired(LayoutDeviceIntSize aSize) {
Rect dst(bounds.X(), bounds.Y(), bounds.Width(), bounds.Height());
Rect src(0, 0, bounds.Width(), bounds.Height());
// The data we get from webrender is upside down. So flip and translate up so
// the image is rightside up. Webrender always does a full screen readback.
#ifdef XP_WIN
// ANGLE with WR does not need y flip
const bool needsYFlip = !WrBridge()->GetCompositorUseANGLE();
#else
const bool needsYFlip = true;
#endif
Matrix m;
if (needsYFlip) {
m = Matrix::Scaling(1.0, -1.0).PostTranslate(0.0, aSize.height);

View File

@ -132,7 +132,8 @@ class RenderCompositor {
// result. It could happen when WebRender renders to multiple overlay layers.
virtual bool MaybeReadback(const gfx::IntSize& aReadbackSize,
const wr::ImageFormat& aReadbackFormat,
const Range<uint8_t>& aReadbackBuffer) {
const Range<uint8_t>& aReadbackBuffer,
bool* aNeedsYFlip) {
return false;
}

View File

@ -940,7 +940,7 @@ uint32_t RenderCompositorANGLE::GetMaxPartialPresentRects() {
bool RenderCompositorANGLE::MaybeReadback(
const gfx::IntSize& aReadbackSize, const wr::ImageFormat& aReadbackFormat,
const Range<uint8_t>& aReadbackBuffer) {
const Range<uint8_t>& aReadbackBuffer, bool* aNeedsYFlip) {
MOZ_ASSERT(aReadbackFormat == wr::ImageFormat::BGRA8);
if (!UseCompositor()) {
@ -1007,6 +1007,10 @@ bool RenderCompositorANGLE::MaybeReadback(
gfxCriticalNote << "Readback took too long: " << latencyMs << " ms";
}
if (aNeedsYFlip) {
*aNeedsYFlip = false;
}
return true;
}

View File

@ -95,7 +95,8 @@ class RenderCompositorANGLE : public RenderCompositor {
bool MaybeReadback(const gfx::IntSize& aReadbackSize,
const wr::ImageFormat& aReadbackFormat,
const Range<uint8_t>& aReadbackBuffer) override;
const Range<uint8_t>& aReadbackBuffer,
bool* aNeedsYFlip) override;
protected:
bool UseCompositor();

View File

@ -98,7 +98,7 @@ bool RenderCompositorNative::ShouldUseNativeCompositor() {
bool RenderCompositorNative::MaybeReadback(
const gfx::IntSize& aReadbackSize, const wr::ImageFormat& aReadbackFormat,
const Range<uint8_t>& aReadbackBuffer) {
const Range<uint8_t>& aReadbackBuffer, bool* aNeedsYFlip) {
if (!ShouldUseNativeCompositor()) {
return false;
}
@ -114,6 +114,10 @@ bool RenderCompositorNative::MaybeReadback(
// current again.
MakeCurrent();
if (aNeedsYFlip) {
*aNeedsYFlip = true;
}
return success;
}

View File

@ -43,7 +43,8 @@ class RenderCompositorNative : public RenderCompositor {
// Does the readback for the ShouldUseNativeCompositor() case.
bool MaybeReadback(const gfx::IntSize& aReadbackSize,
const wr::ImageFormat& aReadbackFormat,
const Range<uint8_t>& aReadbackBuffer) override;
const Range<uint8_t>& aReadbackBuffer,
bool* aNeedsYFlip) override;
// Interface for wr::Compositor
void CompositorBeginFrame() override;

View File

@ -457,7 +457,7 @@ void RenderThread::UpdateAndRender(
const TimeStamp& aStartTime, bool aRender,
const Maybe<gfx::IntSize>& aReadbackSize,
const Maybe<wr::ImageFormat>& aReadbackFormat,
const Maybe<Range<uint8_t>>& aReadbackBuffer) {
const Maybe<Range<uint8_t>>& aReadbackBuffer, bool* aNeedsYFlip) {
AUTO_PROFILER_TRACING_MARKER("Paint", "Composite", GRAPHICS);
MOZ_ASSERT(IsInRenderThread());
MOZ_ASSERT(aRender || aReadbackBuffer.isNothing());
@ -479,8 +479,8 @@ void RenderThread::UpdateAndRender(
wr::RenderedFrameId latestFrameId;
RendererStats stats = {0};
if (aRender) {
latestFrameId = renderer->UpdateAndRender(aReadbackSize, aReadbackFormat,
aReadbackBuffer, &stats);
latestFrameId = renderer->UpdateAndRender(
aReadbackSize, aReadbackFormat, aReadbackBuffer, aNeedsYFlip, &stats);
} else {
renderer->Update();
}

View File

@ -188,7 +188,8 @@ class RenderThread final {
const TimeStamp& aStartTime, bool aRender,
const Maybe<gfx::IntSize>& aReadbackSize,
const Maybe<wr::ImageFormat>& aReadbackFormat,
const Maybe<Range<uint8_t>>& aReadbackBuffer);
const Maybe<Range<uint8_t>>& aReadbackBuffer,
bool* aNeedsYFlip = nullptr);
void Pause(wr::WindowId aWindowId);
bool Resume(wr::WindowId aWindowId);

View File

@ -114,7 +114,8 @@ static void DoWebRenderDisableNativeCompositor(
RenderedFrameId RendererOGL::UpdateAndRender(
const Maybe<gfx::IntSize>& aReadbackSize,
const Maybe<wr::ImageFormat>& aReadbackFormat,
const Maybe<Range<uint8_t>>& aReadbackBuffer, RendererStats* aOutStats) {
const Maybe<Range<uint8_t>>& aReadbackBuffer, bool* aNeedsYFlip,
RendererStats* aOutStats) {
mozilla::widget::WidgetRenderingContext widgetContext;
#if defined(XP_MACOSX)
@ -164,11 +165,18 @@ RenderedFrameId RendererOGL::UpdateAndRender(
MOZ_ASSERT(aReadbackSize.isSome());
MOZ_ASSERT(aReadbackFormat.isSome());
if (!mCompositor->MaybeReadback(aReadbackSize.ref(), aReadbackFormat.ref(),
aReadbackBuffer.ref())) {
aReadbackBuffer.ref(), aNeedsYFlip)) {
wr_renderer_readback(mRenderer, aReadbackSize.ref().width,
aReadbackSize.ref().height, aReadbackFormat.ref(),
&aReadbackBuffer.ref()[0],
aReadbackBuffer.ref().length());
// SWGL and ANGLE both draw the right way up, otherwise we will need a
// flip.
if (aNeedsYFlip) {
*aNeedsYFlip =
!gfx::gfxVars::UseSoftwareWebRender() && !mCompositor->UseANGLE();
}
}
}

View File

@ -61,7 +61,7 @@ class RendererOGL {
RenderedFrameId UpdateAndRender(const Maybe<gfx::IntSize>& aReadbackSize,
const Maybe<wr::ImageFormat>& aReadbackFormat,
const Maybe<Range<uint8_t>>& aReadbackBuffer,
RendererStats* aOutStats);
bool* aNeedsYFlip, RendererStats* aOutStats);
/// This can be called on the render thread only.
void WaitForGPU();

View File

@ -441,17 +441,18 @@ std::vector<WrHitResult> WebRenderAPI::HitTest(const wr::WorldPoint& aPoint) {
void WebRenderAPI::Readback(const TimeStamp& aStartTime, gfx::IntSize size,
const gfx::SurfaceFormat& aFormat,
const Range<uint8_t>& buffer) {
const Range<uint8_t>& buffer, bool* aNeedsYFlip) {
class Readback : public RendererEvent {
public:
explicit Readback(layers::SynchronousTask* aTask, TimeStamp aStartTime,
gfx::IntSize aSize, const gfx::SurfaceFormat& aFormat,
const Range<uint8_t>& aBuffer)
const Range<uint8_t>& aBuffer, bool* aNeedsYFlip)
: mTask(aTask),
mStartTime(aStartTime),
mSize(aSize),
mFormat(aFormat),
mBuffer(aBuffer) {
mBuffer(aBuffer),
mNeedsYFlip(aNeedsYFlip) {
MOZ_COUNT_CTOR(Readback);
}
@ -461,7 +462,7 @@ void WebRenderAPI::Readback(const TimeStamp& aStartTime, gfx::IntSize size,
aRenderThread.UpdateAndRender(aWindowId, VsyncId(), mStartTime,
/* aRender */ true, Some(mSize),
wr::SurfaceFormatToImageFormat(mFormat),
Some(mBuffer));
Some(mBuffer), mNeedsYFlip);
layers::AutoCompleteTask complete(mTask);
}
@ -470,13 +471,15 @@ void WebRenderAPI::Readback(const TimeStamp& aStartTime, gfx::IntSize size,
gfx::IntSize mSize;
gfx::SurfaceFormat mFormat;
const Range<uint8_t>& mBuffer;
bool* mNeedsYFlip;
};
// Disable debug flags during readback. See bug 1436020.
UpdateDebugFlags(0);
layers::SynchronousTask task("Readback");
auto event = MakeUnique<Readback>(&task, aStartTime, size, aFormat, buffer);
auto event = MakeUnique<Readback>(&task, aStartTime, size, aFormat, buffer,
aNeedsYFlip);
// This event will be passed from wr_backend thread to renderer thread. That
// implies that all frame data have been processed when the renderer runs this
// read-back event. Then, we could make sure this read-back event gets the
@ -862,8 +865,7 @@ void WebRenderAPI::RunOnRenderThread(UniquePtr<RendererEvent> aEvent) {
wr_api_send_external_event(mDocHandle, event);
}
DisplayListBuilder::DisplayListBuilder(PipelineId aId,
size_t aCapacity,
DisplayListBuilder::DisplayListBuilder(PipelineId aId, size_t aCapacity,
layers::DisplayItemCache* aCache)
: mCurrentSpaceAndClipChain(wr::RootScrollNodeWithChain()),
mActiveFixedPosTracker(nullptr),

View File

@ -249,7 +249,7 @@ class WebRenderAPI final {
void Readback(const TimeStamp& aStartTime, gfx::IntSize aSize,
const gfx::SurfaceFormat& aFormat,
const Range<uint8_t>& aBuffer);
const Range<uint8_t>& aBuffer, bool* aNeedsYFlip);
void ClearAllCaches();
void EnableNativeCompositor(bool aEnable);

View File

@ -1226,7 +1226,8 @@ class nsWindow::LayerViewSupport final
}
}
void RecvScreenPixels(Shmem&& aMem, const ScreenIntSize& aSize) {
void RecvScreenPixels(Shmem&& aMem, const ScreenIntSize& aSize,
bool aNeedsYFlip) {
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
CaptureRequest request;
java::GeckoResult::LocalRef result = nullptr;
@ -1244,8 +1245,16 @@ class nsWindow::LayerViewSupport final
if (result) {
if (bitmap) {
RefPtr<DataSourceSurface> surf =
FlipScreenPixels(aMem, aSize, request.mSource, request.mOutputSize);
RefPtr<DataSourceSurface> surf;
if (aNeedsYFlip) {
surf = FlipScreenPixels(aMem, aSize, request.mSource,
request.mOutputSize);
} else {
surf = gfx::Factory::CreateWrappingDataSourceSurface(
aMem.get<uint8_t>(),
StrideForFormatAndWidth(SurfaceFormat::B8G8R8A8, aSize.width),
IntSize(aSize.width, aSize.height), SurfaceFormat::B8G8R8A8);
}
if (surf) {
DataSourceSurface::ScopedMap smap(surf, DataSourceSurface::READ);
auto pixels = mozilla::jni::ByteBuffer::New(
@ -2405,10 +2414,11 @@ void nsWindow::UpdateRootFrameMetrics(const ScreenPoint& aScrollOffset,
}
}
void nsWindow::RecvScreenPixels(Shmem&& aMem, const ScreenIntSize& aSize) {
void nsWindow::RecvScreenPixels(Shmem&& aMem, const ScreenIntSize& aSize,
bool aNeedsYFlip) {
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
if (NativePtr<LayerViewSupport>::Locked lvs{mLayerViewSupport}) {
lvs->RecvScreenPixels(std::move(aMem), aSize);
lvs->RecvScreenPixels(std::move(aMem), aSize, aNeedsYFlip);
}
}

View File

@ -325,8 +325,8 @@ class nsWindow final : public nsBaseWidget {
void RecvToolbarAnimatorMessageFromCompositor(int32_t aMessage) override;
void UpdateRootFrameMetrics(const ScreenPoint& aScrollOffset,
const CSSToScreenScale& aZoom) override;
void RecvScreenPixels(mozilla::ipc::Shmem&& aMem,
const ScreenIntSize& aSize) override;
void RecvScreenPixels(mozilla::ipc::Shmem&& aMem, const ScreenIntSize& aSize,
bool aNeedsYFlip) override;
void UpdateDynamicToolbarMaxHeight(mozilla::ScreenIntCoord aHeight) override;
mozilla::ScreenIntCoord GetDynamicToolbarMaxHeight() const override {
return mDynamicToolbarMaxHeight;

View File

@ -433,8 +433,8 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference {
void RecvToolbarAnimatorMessageFromCompositor(int32_t) override{};
void UpdateRootFrameMetrics(const ScreenPoint& aScrollOffset,
const CSSToScreenScale& aZoom) override{};
void RecvScreenPixels(mozilla::ipc::Shmem&& aMem,
const ScreenIntSize& aSize) override{};
void RecvScreenPixels(mozilla::ipc::Shmem&& aMem, const ScreenIntSize& aSize,
bool aNeedsYFlip) override{};
#endif
protected:

View File

@ -2127,7 +2127,8 @@ class nsIWidget : public nsISupports {
* @param aSize size of the buffer in screen pixels.
*/
virtual void RecvScreenPixels(mozilla::ipc::Shmem&& aMem,
const ScreenIntSize& aSize) = 0;
const ScreenIntSize& aSize,
bool aNeedsYFlip) = 0;
virtual void UpdateDynamicToolbarMaxHeight(mozilla::ScreenIntCoord aHeight) {}
virtual mozilla::ScreenIntCoord GetDynamicToolbarMaxHeight() const {