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( |