Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(109)

Side by Side Diff: services/gfx/compositor/graph/scene_def.cc

Issue 1552963002: Initial checkin of the new Mozart compositor. (Closed) Base URL: git@github.com:domokit/mojo.git@moz-11
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "services/gfx/compositor/graph/scene_def.h"
6
7 #include <ostream>
8 #include <sstream>
9
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h"
13 #include "mojo/services/gfx/composition/cpp/logging.h"
14 #include "services/gfx/compositor/graph/snapshot.h"
15 #include "services/gfx/compositor/render/render_image.h"
16 #include "services/gfx/compositor/render/render_layer.h"
17
18 namespace compositor {
19
20 // TODO(jeffbrown): Determine and document a more appropriate size limit
21 // for transferred images as part of the image pipe abstraction instead.
22 static const int32_t kMaxTextureWidth = 65536;
23 static const int32_t kMaxTextureHeight = 65536;
24
25 static void ReleaseMailboxTexture(
26 mojo::gfx::composition::MailboxTextureCallbackPtr callback) {
27 if (callback)
28 callback->OnMailboxTextureReleased();
29 }
30
31 SceneDef::SceneDef(mojo::gfx::composition::SceneTokenPtr scene_token,
32 const std::string& label)
33 : scene_token_(scene_token.Pass()), label_(label) {
34 DCHECK(scene_token_);
35 }
36
37 SceneDef::~SceneDef() {}
38
39 void SceneDef::EnqueueUpdate(mojo::gfx::composition::SceneUpdatePtr update) {
40 DCHECK(update);
41 pending_updates_.push_back(update.Pass());
42 }
43
44 void SceneDef::EnqueuePublish(
45 mojo::gfx::composition::SceneMetadataPtr metadata) {
46 DCHECK(metadata);
47 pending_publications_.emplace_back(new Publication(metadata.Pass()));
48 pending_updates_.swap(pending_publications_.back()->updates);
49 }
50
51 SceneDef::Disposition SceneDef::Present(
52 int64_t presentation_time,
53 const SceneResolver& resolver,
54 const SceneUnavailableSender& unavailable_sender,
55 std::ostream& err) {
56 // Walk backwards through the pending publications to find the index
57 // just beyond the last one which is due to be presented at or before the
58 // presentation time.
59 size_t end = pending_publications_.size();
60 for (;;) {
61 if (!end)
62 return Disposition::kUnchanged;
63 if (pending_publications_[end - 1]->is_due(presentation_time))
64 break; // found last presentable publication
65 end--;
66 }
67
68 // Prepare to apply all publications up to this point.
69 uint32_t version = pending_publications_[end - 1]->metadata->version;
70 if (version_ != version) {
71 version_ = version;
72 formatted_label_cache_.clear();
73 }
74 Invalidate();
75
76 // Apply all updates sequentially.
77 for (size_t index = 0; index < end; ++index) {
78 for (auto& update : pending_publications_[index]->updates) {
79 if (!ApplyUpdate(update.Pass(), resolver, unavailable_sender, err))
80 return Disposition::kFailed;
81 }
82 }
83
84 // Dequeue the publications we processed.
85 pending_publications_.erase(pending_publications_.begin(),
86 pending_publications_.begin() + end);
87
88 // Ensure the scene is in a valid state.
89 if (!Validate(err))
90 return Disposition::kFailed;
91 return Disposition::kSucceeded;
92 }
93
94 bool SceneDef::ApplyUpdate(mojo::gfx::composition::SceneUpdatePtr update,
95 const SceneResolver& resolver,
96 const SceneUnavailableSender& unavailable_sender,
97 std::ostream& err) {
98 DCHECK(update);
99
100 // Update resources.
101 if (update->clear_resources) {
102 resources_.clear();
103 }
104 for (auto it = update->resources.begin(); it != update->resources.end();
105 ++it) {
106 uint32_t resource_id = it.GetKey();
107 mojo::gfx::composition::ResourcePtr& resource_decl = it.GetValue();
108 if (resource_decl) {
109 ResourceDef* resource = CreateResource(resource_id, resource_decl.Pass(),
110 resolver, unavailable_sender, err);
111 if (!resource)
112 return false;
113 resources_[resource_id].reset(resource);
114 } else {
115 resources_.erase(resource_id);
116 }
117 }
118
119 // Update nodes.
120 if (update->clear_nodes) {
121 nodes_.clear();
122 }
123 for (auto it = update->nodes.begin(); it != update->nodes.end(); ++it) {
124 uint32_t node_id = it.GetKey();
125 mojo::gfx::composition::NodePtr& node_decl = it.GetValue();
126 if (node_decl) {
127 NodeDef* node = CreateNode(node_id, node_decl.Pass(), err);
128 if (!node)
129 return false;
130 nodes_[node_id].reset(node);
131 } else {
132 nodes_.erase(node_id);
133 }
134 }
135 return true;
136 }
137
138 bool SceneDef::Validate(std::ostream& err) {
139 // Validate all nodes.
140 // TODO(jeffbrown): Figure out how to do this incrementally if it gets
141 // too expensive to process all nodes each time.
142 root_node_ = nullptr;
143 for (auto& pair : nodes_) {
144 uint32_t node_id = pair.first;
145 NodeDef* node = pair.second.get();
146 if (!node->Validate(this, err))
147 return false;
148 if (node_id == mojo::gfx::composition::kSceneRootNodeId)
149 root_node_ = node;
150 }
151 return true;
152 }
153
154 bool SceneDef::UnlinkReferencedScene(
155 SceneDef* scene,
156 const SceneUnavailableSender& unavailable_sender) {
157 DCHECK(scene);
158
159 bool changed = false;
160 for (auto& pair : resources_) {
161 if (pair.second->type() == ResourceDef::Type::kScene) {
162 auto scene_resource = static_cast<SceneResourceDef*>(pair.second.get());
163 if (scene_resource->referenced_scene() == scene) {
164 scene_resource->clear_referenced_scene();
165 Invalidate();
166 changed = true;
167 unavailable_sender.Run(pair.first);
abarth 2016/01/10 22:55:36 This really looks like a weak pointer with a callb
jeffbrown 2016/01/16 03:28:32 Perhaps, but I don't see a way to set a callback o
168 }
169 }
170 }
171 return changed;
172 }
173
174 bool SceneDef::Snapshot(SnapshotBuilder* snapshot_builder,
175 RenderLayerBuilder* layer_builder) {
176 DCHECK(snapshot_builder);
177 DCHECK(layer_builder);
178
179 // Detect cycles.
180 if (visited_) {
181 if (snapshot_builder->block_log()) {
182 *snapshot_builder->block_log()
183 << "Scene blocked due to recursive cycle: " << FormattedLabel()
184 << std::endl;
185 }
186 return false;
187 }
188
189 // Snapshot the contents of the scene.
190 visited_ = true;
191 bool success = SnapshotInner(snapshot_builder, layer_builder);
192 visited_ = false;
193 return success;
194 }
195
196 bool SceneDef::SnapshotInner(SnapshotBuilder* snapshot_builder,
197 RenderLayerBuilder* layer_builder) {
198 // Note the dependency even if blocked.
199 snapshot_builder->AddSceneDependency(this);
200
201 // Ensure we have a root node.
202 if (!root_node_) {
203 if (snapshot_builder->block_log()) {
204 *snapshot_builder->block_log()
205 << "Scene blocked due because it has no root node: "
206 << FormattedLabel() << std::endl;
207 }
208 return false;
209 }
210
211 // Snapshot and draw the layer.
212 std::shared_ptr<RenderLayer> scene_layer = SnapshotLayer(snapshot_builder);
213 if (!scene_layer)
214 return false;
215 layer_builder->DrawLayer(scene_layer);
216 return true;
217 }
218
219 std::shared_ptr<RenderLayer> SceneDef::SnapshotLayer(
220 SnapshotBuilder* snapshot_builder) {
221 if (cached_layer_)
222 return cached_layer_;
223
224 RenderLayerBuilder scene_layer_builder;
225 scene_layer_builder.PushScene(scene_token_->value, version_);
226 if (!root_node_->Snapshot(snapshot_builder, &scene_layer_builder, this))
227 return nullptr;
228 scene_layer_builder.PopScene();
229
230 // TODO(jeffbrown): Implement caching even when the scene has dependencies.
231 // There are some subtleties to be dealt with to ensure that caches
232 // are properly invalidated and that we don't accidentally cache layers which
233 // bake in decisions which counteract the intended cycle detection and
234 // avoidance behavior. Basically just need better bookkeeping.
abarth 2016/01/10 22:55:36 The DAG is making this harder for you. I'm not su
jeffbrown 2016/01/16 03:28:32 I think the DAG will be quite useful for cross-app
235 std::shared_ptr<RenderLayer> scene_layer = scene_layer_builder.Build();
236 if (!HasSceneResources())
237 cached_layer_ = scene_layer;
238 return scene_layer;
239 }
240
241 void SceneDef::Invalidate() {
242 cached_layer_.reset();
243 }
244
245 bool SceneDef::HasSceneResources() {
246 for (auto& pair : resources_) {
247 if (pair.second->type() == ResourceDef::Type::kScene)
248 return true;
249 }
250 return false;
251 }
252
253 ResourceDef* SceneDef::CreateResource(
254 uint32_t resource_id,
255 mojo::gfx::composition::ResourcePtr resource_decl,
256 const SceneResolver& resolver,
257 const SceneUnavailableSender& unavailable_sender,
258 std::ostream& err) {
259 DCHECK(resource_decl);
260
261 if (resource_decl->is_scene()) {
262 auto& scene_resource_decl = resource_decl->get_scene();
263 DCHECK(scene_resource_decl->scene_token);
264 SceneDef* referenced_scene =
265 resolver.Run(scene_resource_decl->scene_token.get());
266 if (!referenced_scene) {
267 unavailable_sender.Run(resource_id);
268 }
269 return new SceneResourceDef(referenced_scene);
270 }
271
272 if (resource_decl->is_mailbox_texture()) {
273 auto& mailbox_texture_resource_decl = resource_decl->get_mailbox_texture();
274 DCHECK(mailbox_texture_resource_decl->mailbox_name.size() ==
275 GL_MAILBOX_SIZE_CHROMIUM);
276 DCHECK(mailbox_texture_resource_decl->size);
277 int32_t width = mailbox_texture_resource_decl->size->width;
278 int32_t height = mailbox_texture_resource_decl->size->height;
279 if (width < 1 || width > kMaxTextureWidth || height < 1 ||
280 height > kMaxTextureHeight) {
281 err << "MailboxTexture resource has invalid size: "
282 << "resource_id=" << resource_id << ", width=" << width
283 << ", height=" << height;
284 return nullptr;
285 }
286 return new ImageResourceDef(RenderImage::FromMailboxTexture(
287 mailbox_texture_resource_decl->mailbox_name.data(),
288 mailbox_texture_resource_decl->sync_point, width, height,
289 base::MessageLoop::current()->task_runner(),
290 base::Bind(
291 &ReleaseMailboxTexture,
292 base::Passed(mailbox_texture_resource_decl->callback.Pass()))));
293 }
294
295 err << "Unsupported resource type: resource_id=" << resource_id;
296 return nullptr;
297 }
298
299 NodeDef* SceneDef::CreateNode(uint32_t node_id,
300 mojo::gfx::composition::NodePtr node_decl,
301 std::ostream& err) {
302 DCHECK(node_decl);
303
304 NodeOp* op = nullptr;
305 if (node_decl->op) {
306 op = CreateNodeOp(node_id, node_decl->op.Pass(), err);
307 if (!op)
308 return nullptr;
309 }
310
311 return new NodeDef(node_id, node_decl->content_transform.Pass(),
312 node_decl->content_clip.Pass(), node_decl->hit_id,
313 node_decl->combinator, node_decl->child_node_ids.storage(),
314 op);
315 }
316
317 NodeOp* SceneDef::CreateNodeOp(uint32_t node_id,
318 mojo::gfx::composition::NodeOpPtr node_op_decl,
319 std::ostream& err) {
320 DCHECK(node_op_decl);
321
322 if (node_op_decl->is_rect()) {
323 auto& rect_node_op_decl = node_op_decl->get_rect();
324 DCHECK(rect_node_op_decl->content_rect);
325 DCHECK(rect_node_op_decl->color);
326 return new RectNodeOp(*rect_node_op_decl->content_rect,
327 *rect_node_op_decl->color);
328 }
329
330 if (node_op_decl->is_image()) {
331 auto& image_node_op_decl = node_op_decl->get_image();
332 DCHECK(image_node_op_decl->content_rect);
333 return new ImageNodeOp(*image_node_op_decl->content_rect,
334 image_node_op_decl->image_rect.Pass(),
335 image_node_op_decl->image_resource_id,
336 image_node_op_decl->blend.Pass());
337 }
338
339 if (node_op_decl->is_scene()) {
340 auto& scene_node_op_decl = node_op_decl->get_scene();
341 return new SceneNodeOp(scene_node_op_decl->scene_resource_id,
342 scene_node_op_decl->scene_version);
343 }
344
345 if (node_op_decl->is_layer()) {
346 auto& layer_node_op_decl = node_op_decl->get_layer();
347 DCHECK(layer_node_op_decl->layer_size);
348 return new LayerNodeOp(*layer_node_op_decl->layer_size,
349 layer_node_op_decl->blend.Pass());
350 }
351
352 err << "Unsupported node op type: node_id=" << node_id
353 << ", node_op=" << node_op_decl;
354 return nullptr;
355 }
356
357 NodeDef* SceneDef::FindNode(uint32_t node_id) {
358 auto it = nodes_.find(node_id);
359 return it != nodes_.end() ? it->second.get() : nullptr;
360 }
361
362 ResourceDef* SceneDef::FindResource(uint32_t resource_id,
363 ResourceDef::Type resource_type) {
364 auto it = resources_.find(resource_id);
365 return it != resources_.end() && it->second->type() == resource_type
366 ? it->second.get()
367 : nullptr;
368 }
369
370 std::string SceneDef::FormattedLabel() {
371 if (formatted_label_cache_.empty()) {
372 std::ostringstream s;
373 s << "<" << scene_token_->value;
374 if (!label_.empty())
375 s << ":" << label_;
376 s << "/" << version_ << ">";
377 formatted_label_cache_ = s.str();
378 }
379 return formatted_label_cache_;
380 }
381
382 SceneDef::Publication::Publication(
383 mojo::gfx::composition::SceneMetadataPtr metadata)
384 : metadata(metadata.Pass()) {
385 DCHECK(this->metadata);
386 }
387
388 SceneDef::Publication::~Publication() {}
389
390 } // namespace compositor
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698