Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "services/gfx/compositor/graph/snapshot.h" | 5 #include "services/gfx/compositor/graph/snapshot.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "services/gfx/compositor/graph/scene_content.h" | |
| 8 #include "services/gfx/compositor/graph/scene_def.h" | 9 #include "services/gfx/compositor/graph/scene_def.h" |
| 9 #include "services/gfx/compositor/render/render_frame.h" | 10 #include "services/gfx/compositor/render/render_frame.h" |
| 10 #include "services/gfx/compositor/render/render_layer.h" | 11 #include "third_party/skia/include/core/SkPictureRecorder.h" |
| 11 #include "third_party/skia/include/core/SkRect.h" | 12 #include "third_party/skia/include/core/SkRect.h" |
| 12 | 13 |
| 13 namespace compositor { | 14 namespace compositor { |
| 14 | 15 |
| 15 Snapshot::Snapshot() {} | 16 Snapshot::Snapshot() {} |
| 16 | 17 |
| 17 Snapshot::~Snapshot() {} | 18 Snapshot::~Snapshot() {} |
| 18 | 19 |
| 19 bool Snapshot::Invalidate() { | 20 bool Snapshot::Invalidate() { |
| 20 if (valid_) { | 21 if (valid_) { |
| 21 valid_ = false; | 22 valid_ = false; |
| 22 dependencies_.clear(); | 23 dependencies_.clear(); |
| 23 frame_.reset(); | 24 ClearContent(); |
| 24 return true; | 25 return true; |
| 25 } | 26 } |
| 26 return false; | 27 return false; |
| 27 } | 28 } |
| 28 | 29 |
| 29 bool Snapshot::InvalidateScene(SceneDef* scene_def) { | 30 bool Snapshot::InvalidateScene(const SceneDef* scene_def) { |
| 30 DCHECK(scene_def); | 31 DCHECK(scene_def); |
| 32 return valid_ && | |
| 33 dependencies_.find(scene_def->label().token()) != | |
| 34 dependencies_.end() && | |
| 35 Invalidate(); | |
| 36 } | |
| 31 | 37 |
| 32 if (valid_ && dependencies_.find(scene_def) != dependencies_.end()) { | 38 void Snapshot::ClearContent() { |
| 33 return Invalidate(); | 39 root_scene_content_ = nullptr; |
| 34 } | 40 resolved_scene_contents_.clear(); |
| 35 return false; | 41 node_dispositions_.clear(); |
| 42 frame_.reset(); | |
| 43 } | |
| 44 | |
| 45 bool Snapshot::IsBlocked(const NodeDef* node) const { | |
| 46 DCHECK(valid_); | |
| 47 auto it = node_dispositions_.find(node); | |
| 48 DCHECK(it != node_dispositions_.end()); | |
| 49 DCHECK(it->second == Disposition::kSuccess || | |
| 50 it->second == Disposition::kBlocked); | |
| 51 return it->second == Disposition::kBlocked; | |
| 52 } | |
| 53 | |
| 54 const SceneContent* Snapshot::GetResolvedSceneContent( | |
| 55 const SceneNodeDef* scene_node) const { | |
| 56 DCHECK(valid_); | |
| 57 auto it = resolved_scene_contents_.find(scene_node); | |
| 58 DCHECK(it != resolved_scene_contents_.end()); | |
| 59 return it->second.get(); | |
| 36 } | 60 } |
| 37 | 61 |
| 38 SnapshotBuilder::SnapshotBuilder(std::ostream* block_log) | 62 SnapshotBuilder::SnapshotBuilder(std::ostream* block_log) |
| 39 : block_log_(block_log), snapshot_(new Snapshot()) {} | 63 : block_log_(block_log), snapshot_(new Snapshot()) {} |
| 40 | 64 |
| 41 SnapshotBuilder::~SnapshotBuilder() {} | 65 SnapshotBuilder::~SnapshotBuilder() {} |
| 42 | 66 |
| 43 void SnapshotBuilder::AddSceneDependency(SceneDef* scene) { | 67 Snapshot::Disposition SnapshotBuilder::SnapshotNode( |
| 68 const NodeDef* node, | |
| 69 const SceneContent* content) { | |
| 44 DCHECK(snapshot_); | 70 DCHECK(snapshot_); |
| 45 snapshot_->dependencies_.insert(scene); | 71 DCHECK(node); |
| 72 DCHECK(content); | |
| 73 DCHECK(node != content->GetRootNodeIfExists()); | |
| 74 | |
| 75 auto it = snapshot_->node_dispositions_.find(node); | |
| 76 if (it != snapshot_->node_dispositions_.end()) | |
| 77 return it->second; | |
| 78 | |
| 79 Snapshot::Disposition disposition = node->RecordSnapshot(content, this); | |
| 80 snapshot_->node_dispositions_[node] = disposition; | |
| 81 return disposition; | |
| 82 } | |
| 83 | |
| 84 Snapshot::Disposition SnapshotBuilder::SnapshotRootAndDetectCycles( | |
| 85 const NodeDef* node, | |
| 86 const SceneContent* content) { | |
| 87 DCHECK(snapshot_); | |
| 88 DCHECK(node); | |
| 89 DCHECK(content); | |
| 90 DCHECK(node == content->GetRootNodeIfExists()); | |
| 91 | |
| 92 auto it = snapshot_->node_dispositions_.find(node); | |
| 93 if (it != snapshot_->node_dispositions_.end()) { | |
| 94 if (it->second == Snapshot::Disposition::kCycle) | |
| 95 cycle_ = content; // start unwinding, remember where to stop | |
| 96 return it->second; | |
| 97 } | |
| 98 | |
| 99 snapshot_->node_dispositions_[node] = Snapshot::Disposition::kCycle; | |
|
abarth
2016/03/01 17:21:26
There's also a pattern for doing this with one has
jeffbrown
2016/03/02 00:32:16
True. Note that here rehashing may occur after th
| |
| 100 | |
| 101 Snapshot::Disposition disposition = node->RecordSnapshot(content, this); | |
| 102 if (disposition == Snapshot::Disposition::kSuccess) { | |
| 103 snapshot_->node_dispositions_[node] = disposition; | |
| 104 return disposition; | |
| 105 } | |
| 106 | |
| 107 snapshot_->node_dispositions_[node] = Snapshot::Disposition::kBlocked; | |
| 108 | |
| 109 if (disposition == Snapshot::Disposition::kCycle) { | |
| 110 DCHECK(cycle_); | |
| 111 if (block_log_) { | |
| 112 *block_log_ << "Scene blocked because it is part of a cycle: " | |
| 113 << content->FormattedLabel() << std::endl; | |
| 114 } | |
| 115 if (cycle_ == content) { | |
| 116 cycle_ = nullptr; // found the ouroboros tail, stop unwinding | |
| 117 disposition = Snapshot::Disposition::kBlocked; | |
| 118 } | |
| 119 } | |
| 120 return disposition; | |
| 121 } | |
| 122 Snapshot::Disposition SnapshotBuilder::SnapshotScene( | |
| 123 const SceneDef* scene, | |
| 124 uint32_t version, | |
| 125 const SceneNodeDef* referrer_node, | |
| 126 const SceneContent* referrer_content) { | |
| 127 DCHECK(snapshot_); | |
| 128 DCHECK(scene); | |
| 129 DCHECK(referrer_node); | |
| 130 DCHECK(referrer_content); | |
| 131 | |
| 132 // This function should only ever be called once when snapshotting the | |
| 133 // referring |SceneNodeDef| at which point the result will be memoized | |
| 134 // by |SnapshotNode| as usual so reentrance should not occur. | |
| 135 DCHECK(snapshot_->resolved_scene_contents_.find(referrer_node) == | |
| 136 snapshot_->resolved_scene_contents_.end()); | |
| 137 | |
| 138 snapshot_->dependencies_.insert(scene->label().token()); | |
| 139 | |
| 140 const SceneContent* content = scene->FindContent(version); | |
| 141 if (!content) { | |
| 142 if (block_log_) { | |
| 143 *block_log_ << "Scene node blocked because its referenced scene is not " | |
| 144 "available with the requested version: " | |
| 145 << referrer_node->FormattedLabel(referrer_content) | |
| 146 << ", scene " << scene->label().FormattedLabel() | |
| 147 << ", requested version " << version << ", current version " | |
| 148 << scene->version() << std::endl; | |
| 149 } | |
| 150 return Snapshot::Disposition::kBlocked; | |
| 151 } | |
| 152 | |
| 153 const NodeDef* root = content->GetRootNodeIfExists(); | |
| 154 if (!root) { | |
| 155 if (block_log_) { | |
| 156 *block_log_ << "Scene node blocked because its referenced scene has no " | |
| 157 "root node: " | |
| 158 << referrer_node->FormattedLabel(referrer_content) | |
| 159 << ", scene " << content->FormattedLabel() << std::endl; | |
| 160 } | |
| 161 return Snapshot::Disposition::kBlocked; | |
| 162 } | |
| 163 | |
| 164 snapshot_->resolved_scene_contents_[referrer_node] = content; | |
| 165 return SnapshotRootAndDetectCycles(root, content); | |
| 166 } | |
| 167 | |
| 168 Snapshot::Disposition SnapshotBuilder::SnapshotRenderer(const SceneDef* scene) { | |
| 169 DCHECK(!snapshot_->root_scene_content_); | |
| 170 | |
| 171 snapshot_->dependencies_.insert(scene->label().token()); | |
| 172 | |
| 173 const SceneContent* content = | |
| 174 scene->FindContent(mojo::gfx::composition::kSceneVersionNone); | |
| 175 if (!content) { | |
| 176 if (block_log_) { | |
| 177 *block_log_ << "Rendering blocked because the root scene has no content: " | |
| 178 << scene->label().FormattedLabel() << std::endl; | |
| 179 } | |
| 180 return Snapshot::Disposition::kBlocked; | |
| 181 } | |
| 182 | |
| 183 const NodeDef* root = content->GetRootNodeIfExists(); | |
| 184 if (!root) { | |
| 185 if (block_log_) { | |
| 186 *block_log_ << "Rendering blocked the root scene has no root node: " | |
| 187 << content->FormattedLabel() << std::endl; | |
| 188 } | |
| 189 return Snapshot::Disposition::kBlocked; | |
| 190 } | |
| 191 | |
| 192 snapshot_->root_scene_content_ = content; | |
| 193 return SnapshotRootAndDetectCycles(root, content); | |
| 46 } | 194 } |
| 47 | 195 |
| 48 std::unique_ptr<Snapshot> SnapshotBuilder::Build( | 196 std::unique_ptr<Snapshot> SnapshotBuilder::Build( |
| 49 SceneDef* root_scene, | 197 const SceneDef* root_scene, |
| 50 const mojo::Rect& viewport, | 198 const mojo::Rect& viewport, |
| 51 const mojo::gfx::composition::FrameInfo& frame_info) { | 199 const mojo::gfx::composition::FrameInfo& frame_info) { |
| 52 DCHECK(snapshot_); | 200 DCHECK(snapshot_); |
| 53 DCHECK(root_scene); | 201 DCHECK(root_scene); |
| 54 | 202 |
| 55 SkRect sk_viewport = | 203 Snapshot::Disposition disposition = SnapshotRenderer(root_scene); |
| 56 SkRect::MakeXYWH(viewport.x, viewport.y, viewport.width, viewport.height); | 204 DCHECK(!cycle_); // must have properly unwound any cycles by now |
| 57 RenderLayerBuilder layer_builder(&sk_viewport); | 205 |
| 58 if (root_scene->Snapshot(this, &layer_builder)) { | 206 if (disposition == Snapshot::Disposition::kSuccess) { |
| 207 SkRect sk_viewport = SkRect::MakeXYWH(viewport.x, viewport.y, | |
| 208 viewport.width, viewport.height); | |
| 209 SkPictureRecorder recorder; | |
| 210 recorder.beginRecording(sk_viewport); | |
| 211 | |
| 212 const NodeDef* root_node = | |
| 213 snapshot_->root_scene_content_->GetRootNodeIfExists(); | |
| 214 DCHECK(root_node); // otherwise would have failed to snapshot | |
| 215 root_node->RecordPicture(snapshot_->root_scene_content_.get(), | |
| 216 snapshot_.get(), recorder.getRecordingCanvas()); | |
| 217 | |
| 59 snapshot_->frame_ = | 218 snapshot_->frame_ = |
| 60 RenderFrame::Create(layer_builder.Build(), sk_viewport, frame_info); | 219 RenderFrame::Create(skia::AdoptRef(recorder.endRecordingAsPicture()), |
| 220 sk_viewport, frame_info); | |
| 61 } else { | 221 } else { |
| 62 snapshot_->valid_ = false; | 222 snapshot_->ClearContent(); |
| 63 } | 223 } |
| 64 return std::move(snapshot_); | 224 return std::move(snapshot_); |
| 65 } | 225 } |
| 66 | 226 |
| 67 } // namespace compositor | 227 } // namespace compositor |
| OLD | NEW |