| 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
|
| index a23c1088a2376bb4d1a43442fe92e1a62f808248..649c43e8a76ee6362758014d5682353dbe847602 100644
|
| --- a/services/gfx/compositor/graph/scene_def.cc
|
| +++ b/services/gfx/compositor/graph/scene_def.cc
|
| @@ -5,16 +5,14 @@
|
| #include "services/gfx/compositor/graph/scene_def.h"
|
|
|
| #include <ostream>
|
| -#include <utility>
|
|
|
| #include "base/bind.h"
|
| #include "base/logging.h"
|
| #include "base/message_loop/message_loop.h"
|
| #include "base/strings/stringprintf.h"
|
| #include "mojo/services/gfx/composition/cpp/formatting.h"
|
| -#include "services/gfx/compositor/graph/snapshot.h"
|
| +#include "services/gfx/compositor/graph/scene_content.h"
|
| #include "services/gfx/compositor/render/render_image.h"
|
| -#include "services/gfx/compositor/render/render_layer.h"
|
|
|
| namespace compositor {
|
|
|
| @@ -31,11 +29,8 @@ void ReleaseMailboxTexture(
|
| }
|
| } // namespace
|
|
|
| -SceneDef::SceneDef(mojo::gfx::composition::SceneTokenPtr scene_token,
|
| - const std::string& label)
|
| - : scene_token_(scene_token.Pass()), label_(label) {
|
| - DCHECK(scene_token_);
|
| -}
|
| +SceneDef::SceneDef(const SceneLabel& label)
|
| + : label_(label), weak_factory_(this) {}
|
|
|
| SceneDef::~SceneDef() {}
|
|
|
| @@ -68,15 +63,8 @@ SceneDef::Disposition SceneDef::Present(
|
| 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.
|
| + // Apply all updates sequentially up to this point.
|
| + version_ = pending_publications_[end - 1]->metadata->version;
|
| for (size_t index = 0; index < end; ++index) {
|
| for (auto& update : pending_publications_[index]->updates) {
|
| if (!ApplyUpdate(update.Pass(), resolver, unavailable_sender, err))
|
| @@ -88,10 +76,12 @@ SceneDef::Disposition SceneDef::Present(
|
| 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;
|
| + // Rebuild the scene content, gathering all reachable nodes and resources
|
| + // and verifying that everything is correctly linked.
|
| + SceneContentBuilder builder(this, version_, err, resources_.size(),
|
| + nodes_.size());
|
| + content_ = builder.Build();
|
| + return content_ ? Disposition::kSucceeded : Disposition::kFailed;
|
| }
|
|
|
| bool SceneDef::ApplyUpdate(mojo::gfx::composition::SceneUpdatePtr update,
|
| @@ -100,6 +90,12 @@ bool SceneDef::ApplyUpdate(mojo::gfx::composition::SceneUpdatePtr update,
|
| std::ostream& err) {
|
| DCHECK(update);
|
|
|
| + // TODO(jeffbrown): We may be able to reuse some content from previous
|
| + // versions even when the client removes and recreates resources or nodes.
|
| + // To reduce unnecessary churn, consider keeping track of items which have
|
| + // been removed or are being replaced then checking to see whether they
|
| + // really changed.
|
| +
|
| // Update resources.
|
| if (update->clear_resources) {
|
| resources_.clear();
|
| @@ -109,11 +105,11 @@ bool SceneDef::ApplyUpdate(mojo::gfx::composition::SceneUpdatePtr update,
|
| 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);
|
| + scoped_refptr<const ResourceDef> resource = CreateResource(
|
| + resource_id, resource_decl.Pass(), resolver, unavailable_sender, err);
|
| if (!resource)
|
| return false;
|
| - resources_[resource_id].reset(resource);
|
| + resources_[resource_id] = std::move(resource);
|
| } else {
|
| resources_.erase(resource_id);
|
| }
|
| @@ -127,10 +123,11 @@ bool SceneDef::ApplyUpdate(mojo::gfx::composition::SceneUpdatePtr update,
|
| 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);
|
| + scoped_refptr<const NodeDef> node =
|
| + CreateNode(node_id, node_decl.Pass(), err);
|
| if (!node)
|
| return false;
|
| - nodes_[node_id].reset(node);
|
| + nodes_[node_id] = std::move(node);
|
| } else {
|
| nodes_.erase(node_id);
|
| }
|
| @@ -138,22 +135,6 @@ bool SceneDef::ApplyUpdate(mojo::gfx::composition::SceneUpdatePtr update,
|
| 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) {
|
| @@ -162,11 +143,11 @@ bool SceneDef::UnlinkReferencedScene(
|
| 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();
|
| + auto scene_resource =
|
| + static_cast<const SceneResourceDef*>(pair.second.get());
|
| + if (scene_resource->referenced_scene().get() == scene) {
|
| changed = true;
|
| + pair.second = scene_resource->Unlink();
|
| unavailable_sender.Run(pair.first);
|
| }
|
| }
|
| @@ -174,86 +155,7 @@ bool SceneDef::UnlinkReferencedScene(
|
| 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.
|
| - 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(
|
| +scoped_refptr<const ResourceDef> SceneDef::CreateResource(
|
| uint32_t resource_id,
|
| mojo::gfx::composition::ResourcePtr resource_decl,
|
| const SceneResolver& resolver,
|
| @@ -264,12 +166,13 @@ ResourceDef* SceneDef::CreateResource(
|
| 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) {
|
| +
|
| + const mojo::gfx::composition::SceneToken& scene_token =
|
| + *scene_resource_decl->scene_token;
|
| + base::WeakPtr<SceneDef> referenced_scene = resolver.Run(scene_token);
|
| + if (!referenced_scene)
|
| unavailable_sender.Run(resource_id);
|
| - }
|
| - return new SceneResourceDef(referenced_scene);
|
| + return new SceneResourceDef(scene_token, referenced_scene);
|
| }
|
|
|
| if (resource_decl->is_mailbox_texture()) {
|
| @@ -277,8 +180,9 @@ ResourceDef* SceneDef::CreateResource(
|
| 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;
|
| +
|
| + const int32_t width = mailbox_texture_resource_decl->size->width;
|
| + const int32_t height = mailbox_texture_resource_decl->size->height;
|
| if (width < 1 || width > kMaxTextureWidth || height < 1 ||
|
| height > kMaxTextureHeight) {
|
| err << "MailboxTexture resource has invalid size: "
|
| @@ -286,10 +190,12 @@ ResourceDef* SceneDef::CreateResource(
|
| << ", height=" << height;
|
| return nullptr;
|
| }
|
| + const GLbyte* const mailbox_name = reinterpret_cast<GLbyte*>(
|
| + mailbox_texture_resource_decl->mailbox_name.data());
|
| + const GLuint sync_point = mailbox_texture_resource_decl->sync_point;
|
| +
|
| std::shared_ptr<RenderImage> image = RenderImage::CreateFromMailboxTexture(
|
| - reinterpret_cast<GLbyte*>(
|
| - mailbox_texture_resource_decl->mailbox_name.data()),
|
| - mailbox_texture_resource_decl->sync_point, width, height,
|
| + mailbox_name, sync_point, width, height,
|
| base::MessageLoop::current()->task_runner(),
|
| base::Bind(
|
| &ReleaseMailboxTexture,
|
| @@ -307,86 +213,97 @@ ResourceDef* SceneDef::CreateResource(
|
| return nullptr;
|
| }
|
|
|
| -NodeDef* SceneDef::CreateNode(uint32_t node_id,
|
| - mojo::gfx::composition::NodePtr node_decl,
|
| - std::ostream& err) {
|
| +scoped_refptr<const 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;
|
| + mojo::TransformPtr content_transform = node_decl->content_transform.Pass();
|
| + mojo::RectPtr content_clip = node_decl->content_clip.Pass();
|
| + const mojo::gfx::composition::Node::Combinator combinator =
|
| + node_decl->combinator;
|
| + const std::vector<uint32_t>& child_node_ids =
|
| + node_decl->child_node_ids.storage();
|
| +
|
| + if (!node_decl->op) {
|
| + return new NodeDef(node_id, content_transform.Pass(), content_clip.Pass(),
|
| + combinator, child_node_ids);
|
| }
|
|
|
| - 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);
|
| -}
|
| + if (node_decl->op->is_rect()) {
|
| + auto& rect_node_decl = node_decl->op->get_rect();
|
| + DCHECK(rect_node_decl->content_rect);
|
| + DCHECK(rect_node_decl->color);
|
|
|
| -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);
|
| + const mojo::Rect& content_rect = *rect_node_decl->content_rect;
|
| + const mojo::gfx::composition::Color& color = *rect_node_decl->color;
|
| + return new RectNodeDef(node_id, content_transform.Pass(),
|
| + content_clip.Pass(), combinator, child_node_ids,
|
| + content_rect, 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_decl->op->is_image()) {
|
| + auto& image_node_decl = node_decl->op->get_image();
|
| + DCHECK(image_node_decl->content_rect);
|
| +
|
| + const mojo::Rect& content_rect = *image_node_decl->content_rect;
|
| + mojo::RectPtr image_rect = image_node_decl->image_rect.Pass();
|
| + const uint32 image_resource_id = image_node_decl->image_resource_id;
|
| + mojo::gfx::composition::BlendPtr blend = image_node_decl->blend.Pass();
|
| + return new ImageNodeDef(node_id, content_transform.Pass(),
|
| + content_clip.Pass(), combinator, child_node_ids,
|
| + content_rect, image_rect.Pass(), image_resource_id,
|
| + 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_decl->op->is_scene()) {
|
| + auto& scene_node_decl = node_decl->op->get_scene();
|
| +
|
| + const uint32_t scene_resource_id = scene_node_decl->scene_resource_id;
|
| + const uint32_t scene_version = scene_node_decl->scene_version;
|
| + return new SceneNodeDef(node_id, content_transform.Pass(),
|
| + content_clip.Pass(), combinator, child_node_ids,
|
| + scene_resource_id, 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());
|
| + if (node_decl->op->is_layer()) {
|
| + auto& layer_node_decl = node_decl->op->get_layer();
|
| + DCHECK(layer_node_decl->layer_size);
|
| +
|
| + const mojo::Size& layer_size = *layer_node_decl->layer_size;
|
| + mojo::gfx::composition::BlendPtr blend = layer_node_decl->blend.Pass();
|
| + return new LayerNodeDef(node_id, content_transform.Pass(),
|
| + content_clip.Pass(), combinator, child_node_ids,
|
| + layer_size, blend.Pass());
|
| }
|
|
|
| err << "Unsupported node op type: node_id=" << node_id
|
| - << ", node_op=" << node_op_decl;
|
| + << ", node_op=" << node_decl->op;
|
| return nullptr;
|
| }
|
|
|
| -NodeDef* SceneDef::FindNode(uint32_t node_id) {
|
| +const NodeDef* SceneDef::FindNode(uint32_t node_id) const {
|
| 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) {
|
| +const ResourceDef* SceneDef::FindResource(uint32_t resource_id) const {
|
| auto it = resources_.find(resource_id);
|
| - return it != resources_.end() && it->second->type() == resource_type
|
| - ? it->second.get()
|
| - : nullptr;
|
| + return it != resources_.end() ? it->second.get() : nullptr;
|
| }
|
|
|
| -std::string SceneDef::FormattedLabel() {
|
| - if (formatted_label_cache_.empty()) {
|
| - formatted_label_cache_ =
|
| - label_.empty()
|
| - ? base::StringPrintf("<%d/%d>", scene_token_->value, version_)
|
| - : base::StringPrintf("<%d:%s/%d>", scene_token_->value,
|
| - label_.c_str(), version_);
|
| - }
|
| - return formatted_label_cache_;
|
| +const SceneContent* SceneDef::FindContent(uint32_t version) const {
|
| + if (!content_)
|
| + return nullptr;
|
| +
|
| + // TODO(jeffbrown): Consider briefly caching older versions to allow them
|
| + // to be used to provide alternate content for node combinators.
|
| + if (version != mojo::gfx::composition::kSceneVersionNone &&
|
| + version != content_->version() &&
|
| + content_->version() != mojo::gfx::composition::kSceneVersionNone)
|
| + return nullptr;
|
| + return content_.get();
|
| }
|
|
|
| SceneDef::Publication::Publication(
|
|
|