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

Unified 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, 12 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 side-by-side diff with in-line comments
Download patch
Index: services/gfx/compositor/graph/scene_def.cc
diff --git a/services/gfx/compositor/graph/scene_def.cc b/services/gfx/compositor/graph/scene_def.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4791754a69ff7f9d375be956c54109630cf12017
--- /dev/null
+++ b/services/gfx/compositor/graph/scene_def.cc
@@ -0,0 +1,390 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/gfx/compositor/graph/scene_def.h"
+
+#include <ostream>
+#include <sstream>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "mojo/services/gfx/composition/cpp/logging.h"
+#include "services/gfx/compositor/graph/snapshot.h"
+#include "services/gfx/compositor/render/render_image.h"
+#include "services/gfx/compositor/render/render_layer.h"
+
+namespace compositor {
+
+// TODO(jeffbrown): Determine and document a more appropriate size limit
+// for transferred images as part of the image pipe abstraction instead.
+static const int32_t kMaxTextureWidth = 65536;
+static const int32_t kMaxTextureHeight = 65536;
+
+static void ReleaseMailboxTexture(
+ mojo::gfx::composition::MailboxTextureCallbackPtr callback) {
+ if (callback)
+ callback->OnMailboxTextureReleased();
+}
+
+SceneDef::SceneDef(mojo::gfx::composition::SceneTokenPtr scene_token,
+ const std::string& label)
+ : scene_token_(scene_token.Pass()), label_(label) {
+ DCHECK(scene_token_);
+}
+
+SceneDef::~SceneDef() {}
+
+void SceneDef::EnqueueUpdate(mojo::gfx::composition::SceneUpdatePtr update) {
+ DCHECK(update);
+ pending_updates_.push_back(update.Pass());
+}
+
+void SceneDef::EnqueuePublish(
+ mojo::gfx::composition::SceneMetadataPtr metadata) {
+ DCHECK(metadata);
+ pending_publications_.emplace_back(new Publication(metadata.Pass()));
+ pending_updates_.swap(pending_publications_.back()->updates);
+}
+
+SceneDef::Disposition SceneDef::Present(
+ int64_t presentation_time,
+ const SceneResolver& resolver,
+ const SceneUnavailableSender& unavailable_sender,
+ std::ostream& err) {
+ // Walk backwards through the pending publications to find the index
+ // just beyond the last one which is due to be presented at or before the
+ // presentation time.
+ size_t end = pending_publications_.size();
+ for (;;) {
+ if (!end)
+ return Disposition::kUnchanged;
+ if (pending_publications_[end - 1]->is_due(presentation_time))
+ break; // found last presentable publication
+ end--;
+ }
+
+ // Prepare to apply all publications up to this point.
+ uint32_t version = pending_publications_[end - 1]->metadata->version;
+ if (version_ != version) {
+ version_ = version;
+ formatted_label_cache_.clear();
+ }
+ Invalidate();
+
+ // Apply all updates sequentially.
+ for (size_t index = 0; index < end; ++index) {
+ for (auto& update : pending_publications_[index]->updates) {
+ if (!ApplyUpdate(update.Pass(), resolver, unavailable_sender, err))
+ return Disposition::kFailed;
+ }
+ }
+
+ // Dequeue the publications we processed.
+ pending_publications_.erase(pending_publications_.begin(),
+ pending_publications_.begin() + end);
+
+ // Ensure the scene is in a valid state.
+ if (!Validate(err))
+ return Disposition::kFailed;
+ return Disposition::kSucceeded;
+}
+
+bool SceneDef::ApplyUpdate(mojo::gfx::composition::SceneUpdatePtr update,
+ const SceneResolver& resolver,
+ const SceneUnavailableSender& unavailable_sender,
+ std::ostream& err) {
+ DCHECK(update);
+
+ // Update resources.
+ if (update->clear_resources) {
+ resources_.clear();
+ }
+ for (auto it = update->resources.begin(); it != update->resources.end();
+ ++it) {
+ uint32_t resource_id = it.GetKey();
+ mojo::gfx::composition::ResourcePtr& resource_decl = it.GetValue();
+ if (resource_decl) {
+ ResourceDef* resource = CreateResource(resource_id, resource_decl.Pass(),
+ resolver, unavailable_sender, err);
+ if (!resource)
+ return false;
+ resources_[resource_id].reset(resource);
+ } else {
+ resources_.erase(resource_id);
+ }
+ }
+
+ // Update nodes.
+ if (update->clear_nodes) {
+ nodes_.clear();
+ }
+ for (auto it = update->nodes.begin(); it != update->nodes.end(); ++it) {
+ uint32_t node_id = it.GetKey();
+ mojo::gfx::composition::NodePtr& node_decl = it.GetValue();
+ if (node_decl) {
+ NodeDef* node = CreateNode(node_id, node_decl.Pass(), err);
+ if (!node)
+ return false;
+ nodes_[node_id].reset(node);
+ } else {
+ nodes_.erase(node_id);
+ }
+ }
+ return true;
+}
+
+bool SceneDef::Validate(std::ostream& err) {
+ // Validate all nodes.
+ // TODO(jeffbrown): Figure out how to do this incrementally if it gets
+ // too expensive to process all nodes each time.
+ root_node_ = nullptr;
+ for (auto& pair : nodes_) {
+ uint32_t node_id = pair.first;
+ NodeDef* node = pair.second.get();
+ if (!node->Validate(this, err))
+ return false;
+ if (node_id == mojo::gfx::composition::kSceneRootNodeId)
+ root_node_ = node;
+ }
+ return true;
+}
+
+bool SceneDef::UnlinkReferencedScene(
+ SceneDef* scene,
+ const SceneUnavailableSender& unavailable_sender) {
+ DCHECK(scene);
+
+ bool changed = false;
+ for (auto& pair : resources_) {
+ if (pair.second->type() == ResourceDef::Type::kScene) {
+ auto scene_resource = static_cast<SceneResourceDef*>(pair.second.get());
+ if (scene_resource->referenced_scene() == scene) {
+ scene_resource->clear_referenced_scene();
+ Invalidate();
+ changed = true;
+ 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
+ }
+ }
+ }
+ return changed;
+}
+
+bool SceneDef::Snapshot(SnapshotBuilder* snapshot_builder,
+ RenderLayerBuilder* layer_builder) {
+ DCHECK(snapshot_builder);
+ DCHECK(layer_builder);
+
+ // Detect cycles.
+ if (visited_) {
+ if (snapshot_builder->block_log()) {
+ *snapshot_builder->block_log()
+ << "Scene blocked due to recursive cycle: " << FormattedLabel()
+ << std::endl;
+ }
+ return false;
+ }
+
+ // Snapshot the contents of the scene.
+ visited_ = true;
+ bool success = SnapshotInner(snapshot_builder, layer_builder);
+ visited_ = false;
+ return success;
+}
+
+bool SceneDef::SnapshotInner(SnapshotBuilder* snapshot_builder,
+ RenderLayerBuilder* layer_builder) {
+ // Note the dependency even if blocked.
+ snapshot_builder->AddSceneDependency(this);
+
+ // Ensure we have a root node.
+ if (!root_node_) {
+ if (snapshot_builder->block_log()) {
+ *snapshot_builder->block_log()
+ << "Scene blocked due because it has no root node: "
+ << FormattedLabel() << std::endl;
+ }
+ return false;
+ }
+
+ // Snapshot and draw the layer.
+ std::shared_ptr<RenderLayer> scene_layer = SnapshotLayer(snapshot_builder);
+ if (!scene_layer)
+ return false;
+ layer_builder->DrawLayer(scene_layer);
+ return true;
+}
+
+std::shared_ptr<RenderLayer> SceneDef::SnapshotLayer(
+ SnapshotBuilder* snapshot_builder) {
+ if (cached_layer_)
+ return cached_layer_;
+
+ RenderLayerBuilder scene_layer_builder;
+ scene_layer_builder.PushScene(scene_token_->value, version_);
+ if (!root_node_->Snapshot(snapshot_builder, &scene_layer_builder, this))
+ return nullptr;
+ scene_layer_builder.PopScene();
+
+ // TODO(jeffbrown): Implement caching even when the scene has dependencies.
+ // There are some subtleties to be dealt with to ensure that caches
+ // are properly invalidated and that we don't accidentally cache layers which
+ // bake in decisions which counteract the intended cycle detection and
+ // 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
+ std::shared_ptr<RenderLayer> scene_layer = scene_layer_builder.Build();
+ if (!HasSceneResources())
+ cached_layer_ = scene_layer;
+ return scene_layer;
+}
+
+void SceneDef::Invalidate() {
+ cached_layer_.reset();
+}
+
+bool SceneDef::HasSceneResources() {
+ for (auto& pair : resources_) {
+ if (pair.second->type() == ResourceDef::Type::kScene)
+ return true;
+ }
+ return false;
+}
+
+ResourceDef* SceneDef::CreateResource(
+ uint32_t resource_id,
+ mojo::gfx::composition::ResourcePtr resource_decl,
+ const SceneResolver& resolver,
+ const SceneUnavailableSender& unavailable_sender,
+ std::ostream& err) {
+ DCHECK(resource_decl);
+
+ if (resource_decl->is_scene()) {
+ auto& scene_resource_decl = resource_decl->get_scene();
+ DCHECK(scene_resource_decl->scene_token);
+ SceneDef* referenced_scene =
+ resolver.Run(scene_resource_decl->scene_token.get());
+ if (!referenced_scene) {
+ unavailable_sender.Run(resource_id);
+ }
+ return new SceneResourceDef(referenced_scene);
+ }
+
+ if (resource_decl->is_mailbox_texture()) {
+ auto& mailbox_texture_resource_decl = resource_decl->get_mailbox_texture();
+ DCHECK(mailbox_texture_resource_decl->mailbox_name.size() ==
+ GL_MAILBOX_SIZE_CHROMIUM);
+ DCHECK(mailbox_texture_resource_decl->size);
+ int32_t width = mailbox_texture_resource_decl->size->width;
+ int32_t height = mailbox_texture_resource_decl->size->height;
+ if (width < 1 || width > kMaxTextureWidth || height < 1 ||
+ height > kMaxTextureHeight) {
+ err << "MailboxTexture resource has invalid size: "
+ << "resource_id=" << resource_id << ", width=" << width
+ << ", height=" << height;
+ return nullptr;
+ }
+ return new ImageResourceDef(RenderImage::FromMailboxTexture(
+ mailbox_texture_resource_decl->mailbox_name.data(),
+ mailbox_texture_resource_decl->sync_point, width, height,
+ base::MessageLoop::current()->task_runner(),
+ base::Bind(
+ &ReleaseMailboxTexture,
+ base::Passed(mailbox_texture_resource_decl->callback.Pass()))));
+ }
+
+ err << "Unsupported resource type: resource_id=" << resource_id;
+ return nullptr;
+}
+
+NodeDef* SceneDef::CreateNode(uint32_t node_id,
+ mojo::gfx::composition::NodePtr node_decl,
+ std::ostream& err) {
+ DCHECK(node_decl);
+
+ NodeOp* op = nullptr;
+ if (node_decl->op) {
+ op = CreateNodeOp(node_id, node_decl->op.Pass(), err);
+ if (!op)
+ return nullptr;
+ }
+
+ return new NodeDef(node_id, node_decl->content_transform.Pass(),
+ node_decl->content_clip.Pass(), node_decl->hit_id,
+ node_decl->combinator, node_decl->child_node_ids.storage(),
+ op);
+}
+
+NodeOp* SceneDef::CreateNodeOp(uint32_t node_id,
+ mojo::gfx::composition::NodeOpPtr node_op_decl,
+ std::ostream& err) {
+ DCHECK(node_op_decl);
+
+ if (node_op_decl->is_rect()) {
+ auto& rect_node_op_decl = node_op_decl->get_rect();
+ DCHECK(rect_node_op_decl->content_rect);
+ DCHECK(rect_node_op_decl->color);
+ return new RectNodeOp(*rect_node_op_decl->content_rect,
+ *rect_node_op_decl->color);
+ }
+
+ if (node_op_decl->is_image()) {
+ auto& image_node_op_decl = node_op_decl->get_image();
+ DCHECK(image_node_op_decl->content_rect);
+ return new ImageNodeOp(*image_node_op_decl->content_rect,
+ image_node_op_decl->image_rect.Pass(),
+ image_node_op_decl->image_resource_id,
+ image_node_op_decl->blend.Pass());
+ }
+
+ if (node_op_decl->is_scene()) {
+ auto& scene_node_op_decl = node_op_decl->get_scene();
+ return new SceneNodeOp(scene_node_op_decl->scene_resource_id,
+ scene_node_op_decl->scene_version);
+ }
+
+ if (node_op_decl->is_layer()) {
+ auto& layer_node_op_decl = node_op_decl->get_layer();
+ DCHECK(layer_node_op_decl->layer_size);
+ return new LayerNodeOp(*layer_node_op_decl->layer_size,
+ layer_node_op_decl->blend.Pass());
+ }
+
+ err << "Unsupported node op type: node_id=" << node_id
+ << ", node_op=" << node_op_decl;
+ return nullptr;
+}
+
+NodeDef* SceneDef::FindNode(uint32_t node_id) {
+ auto it = nodes_.find(node_id);
+ return it != nodes_.end() ? it->second.get() : nullptr;
+}
+
+ResourceDef* SceneDef::FindResource(uint32_t resource_id,
+ ResourceDef::Type resource_type) {
+ auto it = resources_.find(resource_id);
+ return it != resources_.end() && it->second->type() == resource_type
+ ? it->second.get()
+ : nullptr;
+}
+
+std::string SceneDef::FormattedLabel() {
+ if (formatted_label_cache_.empty()) {
+ std::ostringstream s;
+ s << "<" << scene_token_->value;
+ if (!label_.empty())
+ s << ":" << label_;
+ s << "/" << version_ << ">";
+ formatted_label_cache_ = s.str();
+ }
+ return formatted_label_cache_;
+}
+
+SceneDef::Publication::Publication(
+ mojo::gfx::composition::SceneMetadataPtr metadata)
+ : metadata(metadata.Pass()) {
+ DCHECK(this->metadata);
+}
+
+SceneDef::Publication::~Publication() {}
+
+} // namespace compositor

Powered by Google App Engine
This is Rietveld 408576698