mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Bug 1371037
- Support for record and replay of ClientPaintedLayers on the main thread. r=dvander
This commit is contained in:
parent
adb899a58e
commit
86004b9db3
@ -9,10 +9,13 @@
|
||||
#include "GeckoProfiler.h" // for PROFILER_LABEL
|
||||
#include "client/ClientLayerManager.h" // for ClientLayerManager, etc
|
||||
#include "gfxContext.h" // for gfxContext
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxRect.h" // for gfxRect
|
||||
#include "gfxPrefs.h" // for gfxPrefs
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/gfx/2D.h" // for DrawTarget
|
||||
#include "mozilla/gfx/DrawEventRecorder.h"
|
||||
#include "mozilla/gfx/InlineTranslator.h"
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix
|
||||
#include "mozilla/gfx/Rect.h" // for Rect, IntRect
|
||||
#include "mozilla/gfx/Types.h" // for Float, etc
|
||||
@ -21,7 +24,7 @@
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
|
||||
#include "nsRect.h" // for mozilla::gfx::IntRect
|
||||
#include "gfx2DGlue.h"
|
||||
#include "PaintThread.h"
|
||||
#include "ReadbackProcessor.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -29,17 +32,48 @@ namespace layers {
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
void
|
||||
ClientPaintedLayer::PaintThebes(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates)
|
||||
bool
|
||||
ClientPaintedLayer::EnsureContentClient()
|
||||
{
|
||||
PROFILER_LABEL("ClientPaintedLayer", "PaintThebes",
|
||||
js::ProfileEntry::Category::GRAPHICS);
|
||||
if (!mContentClient) {
|
||||
mContentClient = ContentClient::CreateContentClient(
|
||||
ClientManager()->AsShadowForwarder());
|
||||
|
||||
NS_ASSERTION(ClientManager()->InDrawing(),
|
||||
"Can only draw in drawing phase");
|
||||
|
||||
mContentClient->BeginPaint();
|
||||
if (!mContentClient) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mContentClient->Connect();
|
||||
ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
|
||||
MOZ_ASSERT(mContentClient->GetForwarder());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ClientPaintedLayer::UpdateContentClient(PaintState& aState)
|
||||
{
|
||||
Mutated();
|
||||
|
||||
mValidRegion.Or(mValidRegion, aState.mRegionToDraw);
|
||||
|
||||
ContentClientRemote *contentClientRemote =
|
||||
static_cast<ContentClientRemote *>(mContentClient.get());
|
||||
MOZ_ASSERT(contentClientRemote->GetIPCHandle());
|
||||
|
||||
// Hold(this) ensures this layer is kept alive through the current transaction
|
||||
// The ContentClient assumes this layer is kept alive (e.g., in CreateBuffer),
|
||||
// so deleting this Hold for whatever reason will break things.
|
||||
ClientManager()->Hold(this);
|
||||
contentClientRemote->Updated(aState.mRegionToDraw,
|
||||
mVisibleRegion.ToUnknownRegion(),
|
||||
aState.mDidSelfCopy);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ClientPaintedLayer::GetPaintFlags()
|
||||
{
|
||||
uint32_t flags = RotatedContentBuffer::PAINT_CAN_DRAW_ROTATED;
|
||||
#ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
|
||||
if (ClientManager()->CompositorMightResample()) {
|
||||
@ -51,22 +85,47 @@ ClientPaintedLayer::PaintThebes(nsTArray<ReadbackProcessor::Update>* aReadbackUp
|
||||
}
|
||||
}
|
||||
#endif
|
||||
PaintState state =
|
||||
mContentClient->BeginPaintBuffer(this, flags);
|
||||
mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
|
||||
return flags;
|
||||
}
|
||||
|
||||
if (!state.mRegionToDraw.IsEmpty() && !ClientManager()->GetPaintedLayerCallback()) {
|
||||
bool
|
||||
ClientPaintedLayer::UpdatePaintRegion(PaintState& aState)
|
||||
{
|
||||
mValidRegion.Sub(mValidRegion, aState.mRegionToInvalidate);
|
||||
|
||||
if (!aState.mRegionToDraw.IsEmpty() && !ClientManager()->GetPaintedLayerCallback()) {
|
||||
ClientManager()->SetTransactionIncomplete();
|
||||
mContentClient->EndPaint(nullptr);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// The area that became invalid and is visible needs to be repainted
|
||||
// (this could be the whole visible area if our buffer switched
|
||||
// from RGB to RGBA, because we might need to repaint with
|
||||
// subpixel AA)
|
||||
state.mRegionToInvalidate.And(state.mRegionToInvalidate,
|
||||
GetLocalVisibleRegion().ToUnknownRegion());
|
||||
aState.mRegionToInvalidate.And(aState.mRegionToInvalidate,
|
||||
GetLocalVisibleRegion().ToUnknownRegion());
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ClientPaintedLayer::PaintThebes(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates)
|
||||
{
|
||||
PROFILER_LABEL("ClientPaintedLayer", "PaintThebes",
|
||||
js::ProfileEntry::Category::GRAPHICS);
|
||||
|
||||
NS_ASSERTION(ClientManager()->InDrawing(),
|
||||
"Can only draw in drawing phase");
|
||||
|
||||
mContentClient->BeginPaint();
|
||||
uint32_t flags = GetPaintFlags();
|
||||
|
||||
PaintState state =
|
||||
mContentClient->BeginPaintBuffer(this, flags);
|
||||
|
||||
if (!UpdatePaintRegion(state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool didUpdate = false;
|
||||
RotatedContentBuffer::DrawIterator iter;
|
||||
@ -77,7 +136,7 @@ ClientPaintedLayer::PaintThebes(nsTArray<ReadbackProcessor::Update>* aReadbackUp
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
SetAntialiasingFlags(this, target);
|
||||
|
||||
RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(target);
|
||||
@ -99,36 +158,158 @@ ClientPaintedLayer::PaintThebes(nsTArray<ReadbackProcessor::Update>* aReadbackUp
|
||||
mContentClient->EndPaint(aReadbackUpdates);
|
||||
|
||||
if (didUpdate) {
|
||||
Mutated();
|
||||
UpdateContentClient(state);
|
||||
}
|
||||
}
|
||||
|
||||
mValidRegion.Or(mValidRegion, state.mRegionToDraw);
|
||||
bool
|
||||
ClientPaintedLayer::CanRecordLayer(ReadbackProcessor* aReadback)
|
||||
{
|
||||
// If we don't have a paint thread, this is either not the content
|
||||
// process or the pref is disabled.
|
||||
if (!PaintThread::Get()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ContentClientRemote* contentClientRemote = static_cast<ContentClientRemote*>(mContentClient.get());
|
||||
MOZ_ASSERT(contentClientRemote->GetIPCHandle());
|
||||
// Not supported yet
|
||||
if (aReadback && UsedForReadback()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Hold(this) ensures this layer is kept alive through the current transaction
|
||||
// The ContentClient assumes this layer is kept alive (e.g., in CreateBuffer),
|
||||
// so deleting this Hold for whatever reason will break things.
|
||||
ClientManager()->Hold(this);
|
||||
contentClientRemote->Updated(state.mRegionToDraw,
|
||||
mVisibleRegion.ToUnknownRegion(),
|
||||
state.mDidSelfCopy);
|
||||
// If we have mask layers, we have to render those first
|
||||
// In this case, don't record for now.
|
||||
if (GetMaskLayer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return GetAncestorMaskLayerCount() == 0;
|
||||
}
|
||||
|
||||
already_AddRefed<DrawEventRecorderMemory>
|
||||
ClientPaintedLayer::RecordPaintedLayer()
|
||||
{
|
||||
LayerIntRegion visibleRegion = GetVisibleRegion();
|
||||
LayerIntRect bounds = visibleRegion.GetBounds();
|
||||
LayerIntSize size = bounds.Size();
|
||||
|
||||
if (visibleRegion.IsEmpty()) {
|
||||
if (gfxPrefs::LayersDump()) {
|
||||
printf_stderr("PaintedLayer %p skipping\n", this);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIntRegion regionToPaint;
|
||||
regionToPaint.Sub(mVisibleRegion.ToUnknownRegion(), mValidRegion);
|
||||
|
||||
if (regionToPaint.IsEmpty()) {
|
||||
// Do we ever have to do anything if the region to paint is empty
|
||||
// but we have a painted layer callback?
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!ClientManager()->GetPaintedLayerCallback()) {
|
||||
ClientManager()->SetTransactionIncomplete();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// I know this is slow and we should probably use DrawTargetCapture
|
||||
// But for now, the recording draw target / replay should actually work
|
||||
// Replay for WR happens in Moz2DIMageRenderer
|
||||
IntSize imageSize(size.ToUnknownSize());
|
||||
|
||||
// DrawTargetRecording also plays back the commands while
|
||||
// recording, hence the dummy DT. DummyDT will actually have
|
||||
// the drawn painted layer.
|
||||
RefPtr<DrawEventRecorderMemory> recorder =
|
||||
MakeAndAddRef<DrawEventRecorderMemory>();
|
||||
RefPtr<DrawTarget> dummyDt =
|
||||
Factory::CreateDrawTarget(gfx::BackendType::SKIA, imageSize, gfx::SurfaceFormat::B8G8R8A8);
|
||||
|
||||
RefPtr<DrawTarget> dt =
|
||||
Factory::CreateRecordingDrawTarget(recorder, dummyDt, imageSize);
|
||||
|
||||
dt->ClearRect(Rect(0, 0, imageSize.width, imageSize.height));
|
||||
dt->SetTransform(Matrix().PreTranslate(-bounds.x, -bounds.y));
|
||||
RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(dt);
|
||||
MOZ_ASSERT(ctx); // already checked the target above
|
||||
|
||||
ClientManager()->GetPaintedLayerCallback()(this,
|
||||
ctx,
|
||||
visibleRegion.ToUnknownRegion(),
|
||||
visibleRegion.ToUnknownRegion(),
|
||||
DrawRegionClip::DRAW,
|
||||
nsIntRegion(),
|
||||
ClientManager()->GetPaintedLayerCallbackData());
|
||||
|
||||
return recorder.forget();
|
||||
}
|
||||
|
||||
void
|
||||
ClientPaintedLayer::ReplayPaintedLayer(DrawEventRecorderMemory* aRecorder)
|
||||
{
|
||||
LayerIntRegion visibleRegion = GetVisibleRegion();
|
||||
mContentClient->BeginPaint();
|
||||
|
||||
uint32_t flags = GetPaintFlags();
|
||||
|
||||
PaintState state =
|
||||
mContentClient->BeginPaintBuffer(this, flags);
|
||||
if (!UpdatePaintRegion(state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool didUpdate = false;
|
||||
RotatedContentBuffer::DrawIterator iter;
|
||||
while (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state, &iter)) {
|
||||
if (!target || !target->IsValid()) {
|
||||
if (target) {
|
||||
mContentClient->ReturnDrawTargetToBuffer(target);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
SetAntialiasingFlags(this, target);
|
||||
|
||||
// Draw all the things into the actual content client
|
||||
// This shouldn't exist in the future. For now, its just testing
|
||||
// to make sure we properly record and can replay all the draw
|
||||
// commands
|
||||
std::istream& stream = aRecorder->GetInputStream();
|
||||
InlineTranslator translator(target, nullptr);
|
||||
translator.TranslateRecording(stream);
|
||||
|
||||
mContentClient->ReturnDrawTargetToBuffer(target);
|
||||
didUpdate = true;
|
||||
}
|
||||
|
||||
// ending paint w/o any readback updates
|
||||
// TODO: Fix me
|
||||
mContentClient->EndPaint(nullptr);
|
||||
|
||||
if (didUpdate) {
|
||||
UpdateContentClient(state);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientPaintedLayer::RenderLayerWithReadback(ReadbackProcessor *aReadback)
|
||||
{
|
||||
RenderMaskLayers(this);
|
||||
|
||||
if (!mContentClient) {
|
||||
mContentClient = ContentClient::CreateContentClient(ClientManager()->AsShadowForwarder());
|
||||
if (!mContentClient) {
|
||||
if (CanRecordLayer(aReadback)) {
|
||||
RefPtr<DrawEventRecorderMemory> recorder = RecordPaintedLayer();
|
||||
if (recorder) {
|
||||
if (!EnsureContentClient()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReplayPaintedLayer(recorder);
|
||||
return;
|
||||
}
|
||||
mContentClient->Connect();
|
||||
ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
|
||||
MOZ_ASSERT(mContentClient->GetForwarder());
|
||||
}
|
||||
|
||||
RenderMaskLayers(this);
|
||||
if (!EnsureContentClient()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<ReadbackProcessor::Update> readbackUpdates;
|
||||
|
@ -19,8 +19,11 @@
|
||||
#include "mozilla/layers/PLayerTransaction.h" // for PaintedLayerAttributes
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
namespace gfx {
|
||||
class DrawEventRecorderMemory;
|
||||
};
|
||||
|
||||
namespace layers {
|
||||
class CompositableClient;
|
||||
class ShadowableLayer;
|
||||
class SpecificLayerAttributes;
|
||||
@ -109,6 +112,15 @@ public:
|
||||
|
||||
protected:
|
||||
void PaintThebes(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates);
|
||||
void RecordThebes();
|
||||
bool CanRecordLayer(ReadbackProcessor* aReadback);
|
||||
bool HasMaskLayers();
|
||||
already_AddRefed<gfx::DrawEventRecorderMemory> RecordPaintedLayer();
|
||||
void ReplayPaintedLayer(DrawEventRecorderMemory* aRecorder);
|
||||
bool EnsureContentClient();
|
||||
uint32_t GetPaintFlags();
|
||||
void UpdateContentClient(PaintState& aState);
|
||||
bool UpdatePaintRegion(PaintState& aState);
|
||||
|
||||
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user