| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "services/gfx/compositor/graph/universe.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "mojo/services/gfx/composition/cpp/formatting.h" |
| 9 #include "services/gfx/compositor/graph/scene_content.h" |
| 10 |
| 11 namespace compositor { |
| 12 |
| 13 Universe::Universe() {} |
| 14 |
| 15 Universe::~Universe() {} |
| 16 |
| 17 void Universe::AddScene(const SceneLabel& label) { |
| 18 DCHECK(scenes_.find(label.token()) == scenes_.end()); |
| 19 scenes_.emplace(label.token(), |
| 20 std::unique_ptr<SceneInfo>(new SceneInfo(label))); |
| 21 } |
| 22 |
| 23 void Universe::PresentScene(const scoped_refptr<const SceneContent>& content) { |
| 24 auto it = scenes_.find(content->label().token()); |
| 25 DCHECK(it != scenes_.end()); |
| 26 it->second->content_queue.emplace_front(content); |
| 27 } |
| 28 |
| 29 void Universe::RemoveScene( |
| 30 const mojo::gfx::composition::SceneToken& scene_token) { |
| 31 auto it = scenes_.find(scene_token.value); |
| 32 DCHECK(it != scenes_.end()); |
| 33 scenes_.erase(it); |
| 34 } |
| 35 |
| 36 scoped_refptr<const Snapshot> Universe::SnapshotScene( |
| 37 const mojo::gfx::composition::SceneToken& scene_token, |
| 38 uint32_t version, |
| 39 std::ostream* block_log) { |
| 40 generation_++; |
| 41 CHECK(generation_); |
| 42 |
| 43 Snapshotter snapshotter(this, block_log); |
| 44 scoped_refptr<const Snapshot> snapshot = |
| 45 snapshotter.Build(scene_token, version); |
| 46 |
| 47 // TODO(jeffbrown): Find a better way to prune unused scene versions. |
| 48 // This logic is expensive and will break if there are multiple renderers |
| 49 // involved. Perhaps we should do something like say that all renderers |
| 50 // that live in the same universe should get snapshotted simultaneously. |
| 51 // Or maybe we could be smarter and partition scenes by reachability |
| 52 // using some heuristics to decide which partition should be the scene's |
| 53 // "primary" in case of conflict (so that scenes which only appear on a |
| 54 // single display can be rate-coupled to that display whereas those that |
| 55 // appear in multiple places might experience some resampling). |
| 56 // There's a similar problem lurking in the scheduler mechanism. |
| 57 for (const auto& pair : scenes_) { |
| 58 SceneInfo* info = pair.second.get(); |
| 59 if (info->update_generation != generation_ && |
| 60 info->content_queue.size() > 1) { |
| 61 info->content_queue.erase(info->content_queue.begin() + 1, |
| 62 info->content_queue.end()); |
| 63 } |
| 64 } |
| 65 return snapshot; |
| 66 } |
| 67 |
| 68 Universe::SceneInfo::SceneInfo(const SceneLabel& label) : label(label) {} |
| 69 |
| 70 Universe::SceneInfo::~SceneInfo() {} |
| 71 |
| 72 Universe::Snapshotter::Snapshotter(Universe* universe, std::ostream* block_log) |
| 73 : SnapshotBuilder(block_log), universe_(universe) { |
| 74 DCHECK(universe_); |
| 75 } |
| 76 |
| 77 Universe::Snapshotter::~Snapshotter() { |
| 78 DCHECK(!cycle_); // must have properly unwound any cycles by now |
| 79 } |
| 80 |
| 81 Snapshot::Disposition Universe::Snapshotter::ResolveAndSnapshotScene( |
| 82 const mojo::gfx::composition::SceneToken& scene_token, |
| 83 uint32_t version, |
| 84 scoped_refptr<const SceneContent>* out_content) { |
| 85 auto it = universe_->scenes_.find(scene_token.value); |
| 86 if (it == universe_->scenes_.end()) { |
| 87 if (block_log()) { |
| 88 *block_log() << "Scene not available: " << scene_token << std::endl; |
| 89 } |
| 90 return Snapshot::Disposition::kBlocked; |
| 91 } |
| 92 |
| 93 // TODO(jeffbrown): Ok, this logic is downright terrible. It will end |
| 94 // up doing N^2 work when things are blocked. Replace this with some kind |
| 95 // of sane invalidation mechanism before the system explodes. |
| 96 SceneInfo* info = it->second.get(); |
| 97 if (info->update_generation == universe_->generation_) { |
| 98 if (info->disposition == Snapshot::Disposition::kCycle) { |
| 99 cycle_ = info; // start unwinding, remember where to stop |
| 100 return Snapshot::Disposition::kCycle; |
| 101 } |
| 102 if (info->disposition == Snapshot::Disposition::kBlocked) { |
| 103 if (block_log()) { |
| 104 *block_log() << "Scene blocked (cached prior disposition): " |
| 105 << info->label.FormattedLabel() << std::endl; |
| 106 } |
| 107 return Snapshot::Disposition::kBlocked; |
| 108 } |
| 109 } else { |
| 110 info->update_generation = universe_->generation_; |
| 111 if (info->content_queue.empty()) { |
| 112 if (block_log()) { |
| 113 *block_log() << "Scene has not presented any content: " |
| 114 << info->label.FormattedLabel() << std::endl; |
| 115 } |
| 116 info->disposition = Snapshot::Disposition::kBlocked; |
| 117 return Snapshot::Disposition::kBlocked; |
| 118 } |
| 119 |
| 120 auto it = info->content_queue.begin(); |
| 121 for (;;) { |
| 122 info->disposition = Snapshot::Disposition::kCycle; |
| 123 info->disposition = SnapshotSceneContent((*it).get()); |
| 124 if (info->disposition == Snapshot::Disposition::kSuccess) |
| 125 break; |
| 126 if (info->disposition == Snapshot::Disposition::kCycle) { |
| 127 DCHECK(cycle_); |
| 128 if (block_log()) { |
| 129 *block_log() << "Scene is part of a cycle: " |
| 130 << (*it)->FormattedLabel() << std::endl; |
| 131 } |
| 132 if (cycle_ == info) |
| 133 cycle_ = nullptr; // found the ouroboros tail, stop unwinding |
| 134 info->disposition = Snapshot::Disposition::kBlocked; |
| 135 return Snapshot::Disposition::kCycle; |
| 136 } |
| 137 if (++it == info->content_queue.end()) |
| 138 return Snapshot::Disposition::kBlocked; |
| 139 } |
| 140 if (it + 1 != info->content_queue.end()) |
| 141 info->content_queue.erase(it + 1, info->content_queue.end()); |
| 142 } |
| 143 |
| 144 DCHECK(info->disposition == Snapshot::Disposition::kSuccess); |
| 145 DCHECK(!info->content_queue.empty()); |
| 146 const scoped_refptr<const SceneContent>& content = info->content_queue.back(); |
| 147 if (!content->MatchesVersion(version)) { |
| 148 if (block_log()) { |
| 149 *block_log() << "Scene version mismatch: " << info->label.FormattedLabel() |
| 150 << ", requested version " << version |
| 151 << ", available version " << content->version() << std::endl; |
| 152 } |
| 153 return Snapshot::Disposition::kBlocked; |
| 154 } |
| 155 |
| 156 *out_content = content; |
| 157 return Snapshot::Disposition::kSuccess; |
| 158 } |
| 159 |
| 160 } // namespace compositor |
| OLD | NEW |