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