| Index: services/gfx/compositor/graph/snapshot.cc
|
| diff --git a/services/gfx/compositor/graph/snapshot.cc b/services/gfx/compositor/graph/snapshot.cc
|
| index 935fa2055b790c2a5b402736cb9be84e08e02344..ab4a4478ed2d2302cc30cce06bdf70ab306621fb 100644
|
| --- a/services/gfx/compositor/graph/snapshot.cc
|
| +++ b/services/gfx/compositor/graph/snapshot.cc
|
| @@ -5,9 +5,10 @@
|
| #include "services/gfx/compositor/graph/snapshot.h"
|
|
|
| #include "base/logging.h"
|
| +#include "services/gfx/compositor/graph/scene_content.h"
|
| #include "services/gfx/compositor/graph/scene_def.h"
|
| #include "services/gfx/compositor/render/render_frame.h"
|
| -#include "services/gfx/compositor/render/render_layer.h"
|
| +#include "third_party/skia/include/core/SkPictureRecorder.h"
|
| #include "third_party/skia/include/core/SkRect.h"
|
|
|
| namespace compositor {
|
| @@ -20,19 +21,42 @@ bool Snapshot::Invalidate() {
|
| if (valid_) {
|
| valid_ = false;
|
| dependencies_.clear();
|
| - frame_.reset();
|
| + ClearContent();
|
| return true;
|
| }
|
| return false;
|
| }
|
|
|
| -bool Snapshot::InvalidateScene(SceneDef* scene_def) {
|
| +bool Snapshot::InvalidateScene(const SceneDef* scene_def) {
|
| DCHECK(scene_def);
|
| + return valid_ &&
|
| + dependencies_.find(scene_def->label().token()) !=
|
| + dependencies_.end() &&
|
| + Invalidate();
|
| +}
|
|
|
| - if (valid_ && dependencies_.find(scene_def) != dependencies_.end()) {
|
| - return Invalidate();
|
| - }
|
| - return false;
|
| +void Snapshot::ClearContent() {
|
| + root_scene_content_ = nullptr;
|
| + resolved_scene_contents_.clear();
|
| + node_dispositions_.clear();
|
| + frame_.reset();
|
| +}
|
| +
|
| +bool Snapshot::IsBlocked(const NodeDef* node) const {
|
| + DCHECK(valid_);
|
| + auto it = node_dispositions_.find(node);
|
| + DCHECK(it != node_dispositions_.end());
|
| + DCHECK(it->second == Disposition::kSuccess ||
|
| + it->second == Disposition::kBlocked);
|
| + return it->second == Disposition::kBlocked;
|
| +}
|
| +
|
| +const SceneContent* Snapshot::GetResolvedSceneContent(
|
| + const SceneNodeDef* scene_node) const {
|
| + DCHECK(valid_);
|
| + auto it = resolved_scene_contents_.find(scene_node);
|
| + DCHECK(it != resolved_scene_contents_.end());
|
| + return it->second.get();
|
| }
|
|
|
| SnapshotBuilder::SnapshotBuilder(std::ostream* block_log)
|
| @@ -40,26 +64,164 @@ SnapshotBuilder::SnapshotBuilder(std::ostream* block_log)
|
|
|
| SnapshotBuilder::~SnapshotBuilder() {}
|
|
|
| -void SnapshotBuilder::AddSceneDependency(SceneDef* scene) {
|
| +Snapshot::Disposition SnapshotBuilder::SnapshotNode(
|
| + const NodeDef* node,
|
| + const SceneContent* content) {
|
| + DCHECK(snapshot_);
|
| + DCHECK(node);
|
| + DCHECK(content);
|
| + DCHECK(node != content->GetRootNodeIfExists());
|
| +
|
| + auto it = snapshot_->node_dispositions_.find(node);
|
| + if (it != snapshot_->node_dispositions_.end())
|
| + return it->second;
|
| +
|
| + Snapshot::Disposition disposition = node->RecordSnapshot(content, this);
|
| + snapshot_->node_dispositions_[node] = disposition;
|
| + return disposition;
|
| +}
|
| +
|
| +Snapshot::Disposition SnapshotBuilder::SnapshotRootAndDetectCycles(
|
| + const NodeDef* node,
|
| + const SceneContent* content) {
|
| DCHECK(snapshot_);
|
| - snapshot_->dependencies_.insert(scene);
|
| + DCHECK(node);
|
| + DCHECK(content);
|
| + DCHECK(node == content->GetRootNodeIfExists());
|
| +
|
| + auto storage = snapshot_->node_dispositions_.emplace(
|
| + node, Snapshot::Disposition::kCycle);
|
| + if (!storage.second) {
|
| + if (storage.first->second == Snapshot::Disposition::kCycle)
|
| + cycle_ = content; // start unwinding, remember where to stop
|
| + return storage.first->second;
|
| + }
|
| +
|
| + Snapshot::Disposition disposition = node->RecordSnapshot(content, this);
|
| + if (disposition == Snapshot::Disposition::kSuccess) {
|
| + snapshot_->node_dispositions_[node] = disposition;
|
| + return disposition;
|
| + }
|
| +
|
| + // We cannot reuse the iterator in |storage.first| because it may have
|
| + // been invalidated by the call to |RecordSnapshot| due to rehashing so
|
| + // we must look up the node again just in case.
|
| + snapshot_->node_dispositions_[node] = Snapshot::Disposition::kBlocked;
|
| +
|
| + if (disposition == Snapshot::Disposition::kCycle) {
|
| + DCHECK(cycle_);
|
| + if (block_log_) {
|
| + *block_log_ << "Scene blocked because it is part of a cycle: "
|
| + << content->FormattedLabel() << std::endl;
|
| + }
|
| + if (cycle_ == content) {
|
| + cycle_ = nullptr; // found the ouroboros tail, stop unwinding
|
| + disposition = Snapshot::Disposition::kBlocked;
|
| + }
|
| + }
|
| + return disposition;
|
| +}
|
| +Snapshot::Disposition SnapshotBuilder::SnapshotScene(
|
| + const SceneDef* scene,
|
| + uint32_t version,
|
| + const SceneNodeDef* referrer_node,
|
| + const SceneContent* referrer_content) {
|
| + DCHECK(snapshot_);
|
| + DCHECK(scene);
|
| + DCHECK(referrer_node);
|
| + DCHECK(referrer_content);
|
| +
|
| + // This function should only ever be called once when snapshotting the
|
| + // referring |SceneNodeDef| at which point the result will be memoized
|
| + // by |SnapshotNode| as usual so reentrance should not occur.
|
| + DCHECK(snapshot_->resolved_scene_contents_.find(referrer_node) ==
|
| + snapshot_->resolved_scene_contents_.end());
|
| +
|
| + snapshot_->dependencies_.insert(scene->label().token());
|
| +
|
| + const SceneContent* content = scene->FindContent(version);
|
| + if (!content) {
|
| + if (block_log_) {
|
| + *block_log_ << "Scene node blocked because its referenced scene is not "
|
| + "available with the requested version: "
|
| + << referrer_node->FormattedLabel(referrer_content)
|
| + << ", scene " << scene->label().FormattedLabel()
|
| + << ", requested version " << version << ", current version "
|
| + << scene->version() << std::endl;
|
| + }
|
| + return Snapshot::Disposition::kBlocked;
|
| + }
|
| +
|
| + const NodeDef* root = content->GetRootNodeIfExists();
|
| + if (!root) {
|
| + if (block_log_) {
|
| + *block_log_ << "Scene node blocked because its referenced scene has no "
|
| + "root node: "
|
| + << referrer_node->FormattedLabel(referrer_content)
|
| + << ", scene " << content->FormattedLabel() << std::endl;
|
| + }
|
| + return Snapshot::Disposition::kBlocked;
|
| + }
|
| +
|
| + snapshot_->resolved_scene_contents_[referrer_node] = content;
|
| + return SnapshotRootAndDetectCycles(root, content);
|
| +}
|
| +
|
| +Snapshot::Disposition SnapshotBuilder::SnapshotRenderer(const SceneDef* scene) {
|
| + DCHECK(!snapshot_->root_scene_content_);
|
| +
|
| + snapshot_->dependencies_.insert(scene->label().token());
|
| +
|
| + const SceneContent* content =
|
| + scene->FindContent(mojo::gfx::composition::kSceneVersionNone);
|
| + if (!content) {
|
| + if (block_log_) {
|
| + *block_log_ << "Rendering blocked because the root scene has no content: "
|
| + << scene->label().FormattedLabel() << std::endl;
|
| + }
|
| + return Snapshot::Disposition::kBlocked;
|
| + }
|
| +
|
| + const NodeDef* root = content->GetRootNodeIfExists();
|
| + if (!root) {
|
| + if (block_log_) {
|
| + *block_log_ << "Rendering blocked the root scene has no root node: "
|
| + << content->FormattedLabel() << std::endl;
|
| + }
|
| + return Snapshot::Disposition::kBlocked;
|
| + }
|
| +
|
| + snapshot_->root_scene_content_ = content;
|
| + return SnapshotRootAndDetectCycles(root, content);
|
| }
|
|
|
| std::unique_ptr<Snapshot> SnapshotBuilder::Build(
|
| - SceneDef* root_scene,
|
| + const SceneDef* root_scene,
|
| const mojo::Rect& viewport,
|
| const mojo::gfx::composition::FrameInfo& frame_info) {
|
| DCHECK(snapshot_);
|
| DCHECK(root_scene);
|
|
|
| - SkRect sk_viewport =
|
| - SkRect::MakeXYWH(viewport.x, viewport.y, viewport.width, viewport.height);
|
| - RenderLayerBuilder layer_builder(&sk_viewport);
|
| - if (root_scene->Snapshot(this, &layer_builder)) {
|
| + Snapshot::Disposition disposition = SnapshotRenderer(root_scene);
|
| + DCHECK(!cycle_); // must have properly unwound any cycles by now
|
| +
|
| + if (disposition == Snapshot::Disposition::kSuccess) {
|
| + SkRect sk_viewport = SkRect::MakeXYWH(viewport.x, viewport.y,
|
| + viewport.width, viewport.height);
|
| + SkPictureRecorder recorder;
|
| + recorder.beginRecording(sk_viewport);
|
| +
|
| + const NodeDef* root_node =
|
| + snapshot_->root_scene_content_->GetRootNodeIfExists();
|
| + DCHECK(root_node); // otherwise would have failed to snapshot
|
| + root_node->RecordPicture(snapshot_->root_scene_content_.get(),
|
| + snapshot_.get(), recorder.getRecordingCanvas());
|
| +
|
| snapshot_->frame_ =
|
| - RenderFrame::Create(layer_builder.Build(), sk_viewport, frame_info);
|
| + RenderFrame::Create(skia::AdoptRef(recorder.endRecordingAsPicture()),
|
| + sk_viewport, frame_info);
|
| } else {
|
| - snapshot_->valid_ = false;
|
| + snapshot_->ClearContent();
|
| }
|
| return std::move(snapshot_);
|
| }
|
|
|