summaryrefslogtreecommitdiffstats
path: root/chromium/cc/surfaces/surface_aggregator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/cc/surfaces/surface_aggregator.cc')
-rw-r--r--chromium/cc/surfaces/surface_aggregator.cc250
1 files changed, 250 insertions, 0 deletions
diff --git a/chromium/cc/surfaces/surface_aggregator.cc b/chromium/cc/surfaces/surface_aggregator.cc
new file mode 100644
index 00000000000..72300c0a5db
--- /dev/null
+++ b/chromium/cc/surfaces/surface_aggregator.cc
@@ -0,0 +1,250 @@
+// Copyright 2014 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 "cc/surfaces/surface_aggregator.h"
+
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "cc/output/compositor_frame.h"
+#include "cc/output/delegated_frame_data.h"
+#include "cc/quads/draw_quad.h"
+#include "cc/quads/render_pass_draw_quad.h"
+#include "cc/quads/shared_quad_state.h"
+#include "cc/quads/surface_draw_quad.h"
+#include "cc/surfaces/surface.h"
+#include "cc/surfaces/surface_manager.h"
+
+namespace cc {
+
+SurfaceAggregator::SurfaceAggregator(SurfaceManager* manager)
+ : manager_(manager) {
+ DCHECK(manager_);
+}
+
+SurfaceAggregator::~SurfaceAggregator() {}
+
+DelegatedFrameData* SurfaceAggregator::GetReferencedDataForSurfaceId(
+ SurfaceId surface_id) {
+ Surface* referenced_surface = manager_->GetSurfaceForId(surface_id);
+ if (!referenced_surface)
+ return NULL; // Invalid surface id, skip this quad.
+ CompositorFrame* referenced_frame = referenced_surface->GetEligibleFrame();
+ if (!referenced_frame)
+ return NULL;
+ return referenced_frame->delegated_frame_data.get();
+}
+
+class SurfaceAggregator::RenderPassIdAllocator {
+ public:
+ explicit RenderPassIdAllocator(int surface_id)
+ : surface_id_(surface_id), next_index_(1) {}
+ ~RenderPassIdAllocator() {}
+
+ void AddKnownPass(RenderPass::Id id) {
+ if (id_to_index_map_.find(id) != id_to_index_map_.end())
+ return;
+ id_to_index_map_[id] = next_index_++;
+ }
+
+ RenderPass::Id Remap(RenderPass::Id id) {
+ DCHECK(id_to_index_map_.find(id) != id_to_index_map_.end());
+ return RenderPass::Id(surface_id_, id_to_index_map_[id]);
+ }
+
+ private:
+ base::hash_map<RenderPass::Id, int> id_to_index_map_;
+ int surface_id_;
+ int next_index_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderPassIdAllocator);
+};
+
+RenderPass::Id SurfaceAggregator::RemapPassId(
+ RenderPass::Id surface_local_pass_id,
+ int surface_id) {
+ RenderPassIdAllocator* allocator = render_pass_allocator_map_.get(surface_id);
+ if (!allocator) {
+ allocator = new RenderPassIdAllocator(surface_id);
+ render_pass_allocator_map_.set(surface_id, make_scoped_ptr(allocator));
+ }
+ allocator->AddKnownPass(surface_local_pass_id);
+ return allocator->Remap(surface_local_pass_id);
+}
+
+void SurfaceAggregator::HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad,
+ RenderPass* dest_pass) {
+ SurfaceId surface_id = surface_quad->surface_id;
+ // If this surface's id is already in our referenced set then it creates
+ // a cycle in the graph and should be dropped.
+ if (referenced_surfaces_.count(surface_id.id))
+ return;
+ DelegatedFrameData* referenced_data =
+ GetReferencedDataForSurfaceId(surface_id);
+ if (!referenced_data)
+ return;
+ std::set<int>::iterator it = referenced_surfaces_.insert(surface_id.id).first;
+
+ const RenderPassList& referenced_passes = referenced_data->render_pass_list;
+ for (size_t j = 0; j + 1 < referenced_passes.size(); ++j) {
+ const RenderPass& source = *referenced_passes[j];
+
+ scoped_ptr<RenderPass> copy_pass(RenderPass::Create());
+
+ RenderPass::Id remapped_pass_id = RemapPassId(source.id, surface_id.id);
+
+ copy_pass->SetAll(remapped_pass_id,
+ source.output_rect,
+ source.damage_rect,
+ source.transform_to_root_target,
+ source.has_transparent_background);
+
+ // Contributing passes aggregated in to the pass list need to take the
+ // transform of the surface quad into account to update their transform to
+ // the root surface.
+ // TODO(jamesr): Make sure this is sufficient for surfaces nested several
+ // levels deep and add tests.
+ copy_pass->transform_to_root_target.ConcatTransform(
+ surface_quad->quadTransform());
+
+ CopyQuadsToPass(source.quad_list,
+ source.shared_quad_state_list,
+ gfx::Transform(),
+ copy_pass.get(),
+ surface_id.id);
+
+ dest_pass_list_->push_back(copy_pass.Pass());
+ }
+
+ // TODO(jamesr): Clean up last pass special casing.
+ const RenderPass& last_pass = *referenced_data->render_pass_list.back();
+ const QuadList& quads = last_pass.quad_list;
+
+ // TODO(jamesr): Make sure clipping is enforced.
+ CopyQuadsToPass(quads,
+ last_pass.shared_quad_state_list,
+ surface_quad->quadTransform(),
+ dest_pass,
+ surface_id.id);
+
+ referenced_surfaces_.erase(it);
+}
+
+void SurfaceAggregator::CopySharedQuadState(
+ const SharedQuadState* source_sqs,
+ const gfx::Transform& content_to_target_transform,
+ RenderPass* dest_render_pass) {
+ SharedQuadState* copy_shared_quad_state =
+ dest_render_pass->CreateAndAppendSharedQuadState();
+ copy_shared_quad_state->CopyFrom(source_sqs);
+ // content_to_target_transform contains any transformation that may exist
+ // between the context that these quads are being copied from (i.e. the
+ // surface's draw transform when aggregated from within a surface) to the
+ // target space of the pass. This will be identity except when copying the
+ // root draw pass from a surface into a pass when the surface draw quad's
+ // transform is not identity.
+ copy_shared_quad_state->content_to_target_transform.ConcatTransform(
+ content_to_target_transform);
+}
+
+void SurfaceAggregator::CopyQuadsToPass(
+ const QuadList& source_quad_list,
+ const SharedQuadStateList& source_shared_quad_state_list,
+ const gfx::Transform& content_to_target_transform,
+ RenderPass* dest_pass,
+ int surface_id) {
+ const SharedQuadState* last_copied_source_shared_quad_state = NULL;
+
+ for (size_t i = 0, sqs_i = 0; i < source_quad_list.size(); ++i) {
+ DrawQuad* quad = source_quad_list[i];
+ while (quad->shared_quad_state != source_shared_quad_state_list[sqs_i]) {
+ ++sqs_i;
+ DCHECK_LT(sqs_i, source_shared_quad_state_list.size());
+ }
+ DCHECK_EQ(quad->shared_quad_state, source_shared_quad_state_list[sqs_i]);
+
+ if (quad->material == DrawQuad::SURFACE_CONTENT) {
+ const SurfaceDrawQuad* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
+ HandleSurfaceQuad(surface_quad, dest_pass);
+ } else {
+ if (quad->shared_quad_state != last_copied_source_shared_quad_state) {
+ CopySharedQuadState(
+ quad->shared_quad_state, content_to_target_transform, dest_pass);
+ last_copied_source_shared_quad_state = quad->shared_quad_state;
+ }
+ if (quad->material == DrawQuad::RENDER_PASS) {
+ const RenderPassDrawQuad* pass_quad =
+ RenderPassDrawQuad::MaterialCast(quad);
+ RenderPass::Id original_pass_id = pass_quad->render_pass_id;
+ RenderPass::Id remapped_pass_id =
+ RemapPassId(original_pass_id, surface_id);
+
+ dest_pass->quad_list.push_back(
+ pass_quad->Copy(dest_pass->shared_quad_state_list.back(),
+ remapped_pass_id).PassAs<DrawQuad>());
+ } else {
+ dest_pass->quad_list.push_back(
+ quad->Copy(dest_pass->shared_quad_state_list.back()));
+ }
+ }
+ }
+}
+
+void SurfaceAggregator::CopyPasses(const RenderPassList& source_pass_list,
+ int surface_id) {
+ for (size_t i = 0; i < source_pass_list.size(); ++i) {
+ const RenderPass& source = *source_pass_list[i];
+
+ scoped_ptr<RenderPass> copy_pass(RenderPass::Create());
+
+ RenderPass::Id remapped_pass_id = RemapPassId(source.id, surface_id);
+
+ copy_pass->SetAll(remapped_pass_id,
+ source.output_rect,
+ source.damage_rect,
+ source.transform_to_root_target,
+ source.has_transparent_background);
+
+ CopyQuadsToPass(source.quad_list,
+ source.shared_quad_state_list,
+ gfx::Transform(),
+ copy_pass.get(),
+ surface_id);
+
+ dest_pass_list_->push_back(copy_pass.Pass());
+ }
+}
+
+scoped_ptr<CompositorFrame> SurfaceAggregator::Aggregate(SurfaceId surface_id) {
+ Surface* surface = manager_->GetSurfaceForId(surface_id);
+ if (!surface)
+ return scoped_ptr<CompositorFrame>();
+ CompositorFrame* root_surface_frame = surface->GetEligibleFrame();
+ if (!root_surface_frame)
+ return scoped_ptr<CompositorFrame>();
+
+ scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+ frame->delegated_frame_data = make_scoped_ptr(new DelegatedFrameData);
+
+ DCHECK(root_surface_frame->delegated_frame_data);
+
+ const RenderPassList& source_pass_list =
+ root_surface_frame->delegated_frame_data->render_pass_list;
+
+ std::set<int>::iterator it = referenced_surfaces_.insert(surface_id.id).first;
+
+ dest_pass_list_ = &frame->delegated_frame_data->render_pass_list;
+ CopyPasses(source_pass_list, surface_id.id);
+
+ referenced_surfaces_.erase(it);
+ DCHECK(referenced_surfaces_.empty());
+
+ dest_pass_list_ = NULL;
+
+ // TODO(jamesr): Aggregate all resource references into the returned frame's
+ // resource list.
+
+ return frame.Pass();
+}
+
+} // namespace cc