fune/layout/painting/WindowRenderer.h
Nicolas Silva cb6ac0df62 Bug 1690619 - Keep track of where the request to rendering something comes from. r=gfx-reviewers,mstange
This patch adds plumbing to keep track of why we request frames to be rendered.
This information is then displayed in gecko profile markers on the renderer thread as well as in profiler HUD counters (See "Render reasons" in profiler.rs).

Differential Revision: https://phabricator.services.mozilla.com/D127274
2021-10-05 12:54:39 +00:00

284 lines
9.7 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_PAINTING_WINDOWRENDERER_H
#define MOZILLA_PAINTING_WINDOWRENDERER_H
#include "mozilla/webrender/webrender_ffi.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/dom/Animation.h" // for Animation
#include "mozilla/layers/ScrollableLayerGuid.h" // for ScrollableLayerGuid, ScrollableLayerGuid::ViewID
#include "mozilla/ScrollPositionUpdate.h" // for ScrollPositionUpdate
#include "nsRefPtrHashtable.h" // for nsRefPtrHashtable
#include "gfxContext.h"
namespace mozilla {
namespace layers {
class LayerManager;
class WebRenderLayerManager;
class KnowsCompositor;
class CompositorBridgeChild;
class FrameUniformityData;
class PersistentBufferProvider;
} // namespace layers
class FallbackRenderer;
class nsDisplayListBuilder;
class nsDisplayList;
class FrameRecorder {
public:
/**
* Record (and return) frame-intervals and paint-times for frames which were
* presented between calling StartFrameTimeRecording and
* StopFrameTimeRecording.
*
* - Uses a cyclic buffer and serves concurrent consumers, so if Stop is
* called too late
* (elements were overwritten since Start), result is considered invalid
* and hence empty.)
* - Buffer is capable of holding 10 seconds @ 60fps (or more if frames were
* less frequent).
* Can be changed (up to 1 hour) via pref:
* toolkit.framesRecording.bufferSize.
* - Note: the first frame-interval may be longer than expected because last
* frame
* might have been presented some time before calling
* StartFrameTimeRecording.
*/
/**
* Returns a handle which represents current recording start position.
*/
virtual uint32_t StartFrameTimeRecording(int32_t aBufferSize);
/**
* Clears, then populates aFrameIntervals with the recorded frame timing
* data. The array will be empty if data was overwritten since
* aStartIndex was obtained.
*/
virtual void StopFrameTimeRecording(uint32_t aStartIndex,
nsTArray<float>& aFrameIntervals);
void RecordFrame();
private:
struct FramesTimingRecording {
// Stores state and data for frame intervals and paint times recording.
// see LayerManager::StartFrameTimeRecording() at Layers.cpp for more
// details.
FramesTimingRecording()
: mNextIndex(0),
mLatestStartIndex(0),
mCurrentRunStartIndex(0),
mIsPaused(true) {}
nsTArray<float> mIntervals;
TimeStamp mLastFrameTime;
uint32_t mNextIndex;
uint32_t mLatestStartIndex;
uint32_t mCurrentRunStartIndex;
bool mIsPaused;
};
FramesTimingRecording mRecording;
};
/**
* WindowRenderer is the retained rendering object owned by an nsIWidget for
* drawing the contents of that window, the role previously handled by
* LayerManager.
*
* It can be WebRender, (deprecated) Layers, or an immediate-mode
* FallbackRenderer.
*
* The intention is for LayerManager to be removed entirely in the near future,
* with WebRender inheriting directly from this class. It is likely that more
* cleanup can be done once that happens.
*/
class WindowRenderer : public FrameRecorder {
NS_INLINE_DECL_REFCOUNTING(WindowRenderer)
public:
// Cast to implementation types.
virtual layers::WebRenderLayerManager* AsWebRender() { return nullptr; }
virtual FallbackRenderer* AsFallback() { return nullptr; }
// Required functionality
/**
* Start a new transaction. Nested transactions are not allowed so
* there must be no transaction currently in progress.
* This transaction will update the state of the window from which
* this LayerManager was obtained.
*/
virtual bool BeginTransaction(const nsCString& aURL = nsCString()) = 0;
enum EndTransactionFlags {
END_DEFAULT = 0,
END_NO_IMMEDIATE_REDRAW = 1 << 0, // Do not perform the drawing phase
END_NO_COMPOSITE =
1 << 1, // Do not composite after drawing painted layer contents.
END_NO_REMOTE_COMPOSITE = 1 << 2 // Do not schedule a composition with a
// remote Compositor, if one exists.
};
/**
* Attempts to end an "empty transaction". There must have been no
* changes to the layer tree since the BeginTransaction().
* It's possible for this to fail; PaintedLayers may need to be updated
* due to VRAM data being lost, for example. In such cases this method
* returns false, and the caller must proceed with a normal layer tree
* update and EndTransaction.
*/
virtual bool EndEmptyTransaction(
EndTransactionFlags aFlags = END_DEFAULT) = 0;
virtual void Destroy() {}
/**
* Type of layer manager this is. This is to be used sparsely in order to
* avoid a lot of Layers backend specific code. It should be used only when
* Layers backend specific functionality is necessary.
*/
virtual layers::LayersBackend GetBackendType() = 0;
/**
* Type of layers backend that will be used to composite this layer tree.
* When compositing is done remotely, then this returns the layers type
* of the compositor.
*/
virtual layers::LayersBackend GetCompositorBackendType() {
return GetBackendType();
}
/**
* Checks if we need to invalidate the OS widget to trigger
* painting when updating this renderer.
*/
virtual bool NeedsWidgetInvalidation() { return true; }
/**
* Make sure that the previous transaction has been entirely
* completed.
*
* Note: This may sychronously wait on a remote compositor
* to complete rendering.
*/
virtual void FlushRendering(wr::RenderReasons aReasons) {}
/**
* Make sure that the previous transaction has been
* received. This will synchronsly wait on a remote compositor.
*/
virtual void WaitOnTransactionProcessed() {}
virtual bool IsCompositingCheap() { return true; }
/**
* returns the maximum texture size on this layer backend, or INT32_MAX
* if there is no maximum
*/
virtual int32_t GetMaxTextureSize() const { return INT32_MAX; }
/**
* Return the name of the layer manager's backend.
*/
virtual void GetBackendName(nsAString& aName) = 0;
virtual void GetFrameUniformity(layers::FrameUniformityData* aOutData) {}
virtual bool AddPendingScrollUpdateForNextTransaction(
layers::ScrollableLayerGuid::ViewID aScrollId,
const ScrollPositionUpdate& aUpdateInfo) {
return false;
}
/**
* Creates a PersistentBufferProvider for use with canvas which is optimized
* for inter-operating with this layermanager.
*/
virtual already_AddRefed<layers::PersistentBufferProvider>
CreatePersistentBufferProvider(const mozilla::gfx::IntSize& aSize,
mozilla::gfx::SurfaceFormat aFormat);
// Helper wrappers around cast to impl and then cast again.
virtual layers::KnowsCompositor* AsKnowsCompositor() { return nullptr; }
virtual layers::CompositorBridgeChild* GetCompositorBridgeChild() {
return nullptr;
}
// Provided functionality
void AddPartialPrerenderedAnimation(uint64_t aCompositorAnimationId,
dom::Animation* aAnimation);
void RemovePartialPrerenderedAnimation(uint64_t aCompositorAnimationId,
dom::Animation* aAnimation);
void UpdatePartialPrerenderedAnimations(
const nsTArray<uint64_t>& aJankedAnimations);
const TimeStamp& GetAnimationReadyTime() const { return mAnimationReadyTime; }
protected:
virtual ~WindowRenderer() = default;
// Transform animations which are not fully pre-rendered because it's on a
// large frame. We need to update the pre-rendered area once after we tried
// to composite area which is outside of the pre-rendered area on the
// compositor.
nsRefPtrHashtable<nsUint64HashKey, dom::Animation>
mPartialPrerenderedAnimations;
// The time when painting most recently finished. This is recorded so that
// we can time any play-pending animations from this point.
TimeStamp mAnimationReadyTime;
};
/**
* FallbackRenderer is non-retained renderer that acts as a direct wrapper
* around calling Paint on the provided DisplayList. This is used for cases
* where initializing WebRender is too costly, and we don't need
* retaining/invalidation (like small popup windows).
*
* It doesn't support any sort of EmptyTransaction, and only draws during
* EndTransaction if a composite is requested (no END_NO_COMPOSITE flag
* provided)
*/
class FallbackRenderer : public WindowRenderer {
public:
FallbackRenderer* AsFallback() override { return this; }
void SetTarget(gfxContext* aContext, layers::BufferMode aDoubleBuffering);
bool BeginTransaction(const nsCString& aURL = nsCString()) override;
bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) override {
return false;
}
layers::LayersBackend GetBackendType() override {
return layers::LayersBackend::LAYERS_NONE;
}
virtual void GetBackendName(nsAString& name) override {
name.AssignLiteral("Fallback");
}
bool IsCompositingCheap() override { return false; }
void EndTransactionWithColor(const nsIntRect& aRect,
const gfx::DeviceColor& aColor);
void EndTransactionWithList(nsDisplayListBuilder* aBuilder,
nsDisplayList* aList,
int32_t aAppUnitsPerDevPixel,
EndTransactionFlags aFlags);
RefPtr<gfxContext> mTarget;
layers::BufferMode mBufferMode;
};
} // namespace mozilla
#endif /* MOZILLA_PAINTING_WINDOWRENDERER_H */