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

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

Powered by Google App Engine
This is Rietveld 408576698