Commit 6a8b3390 authored by jamesr@chromium.org's avatar jamesr@chromium.org

Initial surface aggregator implementation

BUG=334876

Review URL: https://codereview.chromium.org/139763003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@247598 0039d316-1c4b-4281-b951-d872f2087c98
parent b23624b1
...@@ -458,6 +458,7 @@ ...@@ -458,6 +458,7 @@
'cc', 'cc',
'<(DEPTH)/base/base.gyp:base', '<(DEPTH)/base/base.gyp:base',
'<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
'<(DEPTH)/skia/skia.gyp:skia',
'<(DEPTH)/ui/gfx/gfx.gyp:gfx', '<(DEPTH)/ui/gfx/gfx.gyp:gfx',
'<(DEPTH)/ui/gfx/gfx.gyp:gfx_geometry', '<(DEPTH)/ui/gfx/gfx.gyp:gfx_geometry',
], ],
...@@ -467,6 +468,8 @@ ...@@ -467,6 +468,8 @@
'sources': [ 'sources': [
'surfaces/surface.cc', 'surfaces/surface.cc',
'surfaces/surface.h', 'surfaces/surface.h',
'surfaces/surface_aggregator.cc',
'surfaces/surface_aggregator.h',
'surfaces/surface_manager.cc', 'surfaces/surface_manager.cc',
'surfaces/surface_manager.h', 'surfaces/surface_manager.h',
'surfaces/surfaces_export.h', 'surfaces/surfaces_export.h',
......
...@@ -106,6 +106,9 @@ ...@@ -106,6 +106,9 @@
], ],
'cc_surfaces_unit_tests_source_files': [ 'cc_surfaces_unit_tests_source_files': [
'surfaces/surface_unittest.cc', 'surfaces/surface_unittest.cc',
'surfaces/surface_aggregator_unittest.cc',
'surfaces/surface_aggregator_test_helpers.cc',
'surfaces/surface_aggregator_test_helpers.h',
], ],
'cc_tests_support_files': [ 'cc_tests_support_files': [
'test/animation_test_common.cc', 'test/animation_test_common.cc',
......
...@@ -17,6 +17,11 @@ class Value; ...@@ -17,6 +17,11 @@ class Value;
namespace cc { namespace cc {
// SharedQuadState holds a set of properties that are common across multiple
// DrawQuads. It's purely an optimization - the properties behave in exactly the
// same way as if they were replicated on each DrawQuad. A given SharedQuadState
// can only be shared by DrawQuads that are adjacent in their RenderPass'
// QuadList.
class CC_EXPORT SharedQuadState { class CC_EXPORT SharedQuadState {
public: public:
static scoped_ptr<SharedQuadState> Create(); static scoped_ptr<SharedQuadState> Create();
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "cc/surfaces/surface.h" #include "cc/surfaces/surface.h"
#include "cc/output/compositor_frame.h"
#include "cc/surfaces/surface_manager.h" #include "cc/surfaces/surface_manager.h"
namespace cc { namespace cc {
...@@ -21,4 +22,10 @@ Surface::~Surface() { ...@@ -21,4 +22,10 @@ Surface::~Surface() {
manager_->DeregisterSurface(surface_id_); manager_->DeregisterSurface(surface_id_);
} }
void Surface::QueueFrame(scoped_ptr<CompositorFrame> frame) {
current_frame_ = frame.Pass();
}
CompositorFrame* Surface::GetEligibleFrame() { return current_frame_.get(); }
} // namespace cc } // namespace cc
...@@ -6,10 +6,12 @@ ...@@ -6,10 +6,12 @@
#define CC_SURFACES_SURFACE_H_ #define CC_SURFACES_SURFACE_H_
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "cc/surfaces/surfaces_export.h" #include "cc/surfaces/surfaces_export.h"
#include "ui/gfx/size.h" #include "ui/gfx/size.h"
namespace cc { namespace cc {
class CompositorFrame;
class SurfaceManager; class SurfaceManager;
class SurfaceClient; class SurfaceClient;
...@@ -23,11 +25,17 @@ class CC_SURFACES_EXPORT Surface { ...@@ -23,11 +25,17 @@ class CC_SURFACES_EXPORT Surface {
const gfx::Size& size() const { return size_; } const gfx::Size& size() const { return size_; }
int surface_id() const { return surface_id_; } int surface_id() const { return surface_id_; }
void QueueFrame(scoped_ptr<CompositorFrame> frame);
// Returns the most recent frame that is eligible to be rendered.
CompositorFrame* GetEligibleFrame();
private: private:
SurfaceManager* manager_; SurfaceManager* manager_;
SurfaceClient* client_; SurfaceClient* client_;
gfx::Size size_; gfx::Size size_;
int surface_id_; int surface_id_;
// TODO(jamesr): Support multiple frames in flight.
scoped_ptr<CompositorFrame> current_frame_;
DISALLOW_COPY_AND_ASSIGN(Surface); DISALLOW_COPY_AND_ASSIGN(Surface);
}; };
......
// 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(
int 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) {
int 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))
return;
DelegatedFrameData* referenced_data =
GetReferencedDataForSurfaceID(surface_id);
if (!referenced_data)
return;
std::set<int>::iterator it = referenced_surfaces_.insert(surface_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);
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,
copy_pass.get(),
surface_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;
for (size_t j = 0; j < last_pass.shared_quad_state_list.size(); ++j) {
dest_pass->shared_quad_state_list.push_back(
last_pass.shared_quad_state_list[j]->Copy());
}
// TODO(jamesr): Map transform correctly for quads in the referenced
// surface into this pass's space.
// TODO(jamesr): Make sure clipping is enforced.
CopyQuadsToPass(
quads, last_pass.shared_quad_state_list, dest_pass, surface_id);
referenced_surfaces_.erase(it);
}
void SurfaceAggregator::CopyQuadsToPass(
const QuadList& source_quad_list,
const SharedQuadStateList& source_shared_quad_state_list,
RenderPass* dest_pass,
int surface_id) {
for (size_t j = 0; j < source_shared_quad_state_list.size(); ++j) {
dest_pass->shared_quad_state_list.push_back(
source_shared_quad_state_list[j]->Copy());
}
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_LT(sqs_i, dest_pass->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->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[sqs_i],
remapped_pass_id).PassAs<DrawQuad>());
} else {
dest_pass->quad_list.push_back(
quad->Copy(dest_pass->shared_quad_state_list[sqs_i]));
}
}
}
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,
copy_pass.get(),
surface_id);
dest_pass_list_->push_back(copy_pass.Pass());
}
}
scoped_ptr<CompositorFrame> SurfaceAggregator::Aggregate(int 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;
referenced_surfaces_.insert(surface_id);
dest_pass_list_ = &frame->delegated_frame_data->render_pass_list;
CopyPasses(source_pass_list, surface_id);
referenced_surfaces_.clear();
dest_pass_list_ = NULL;
// TODO(jamesr): Aggregate all resource references into the returned frame's
// resource list.
return frame.Pass();
}
} // namespace cc
// 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.
#ifndef CC_SURFACES_SURFACE_AGGREGATOR_H_
#define CC_SURFACES_SURFACE_AGGREGATOR_H_
#include <set>
#include "base/containers/scoped_ptr_hash_map.h"
#include "base/memory/scoped_ptr.h"
#include "cc/quads/render_pass.h"
#include "cc/surfaces/surfaces_export.h"
namespace cc {
class CompositorFrame;
class DelegatedFrameData;
class SurfaceDrawQuad;
class SurfaceManager;
class CC_SURFACES_EXPORT SurfaceAggregator {
public:
explicit SurfaceAggregator(SurfaceManager* manager);
~SurfaceAggregator();
scoped_ptr<CompositorFrame> Aggregate(int surface_id);
private:
DelegatedFrameData* GetReferencedDataForSurfaceID(int surface_id);
RenderPass::Id RemapPassId(RenderPass::Id surface_local_pass_id,
int surface_id);
void HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad,
RenderPass* dest_pass);
void CopyQuadsToPass(const QuadList& source_quad_list,
const SharedQuadStateList& source_shared_quad_state_list,
RenderPass* dest_pass,
int surface_id);
void CopyPasses(const RenderPassList& source_pass_list, int surface_id);
SurfaceManager* manager_;
class RenderPassIdAllocator;
typedef base::ScopedPtrHashMap<int, RenderPassIdAllocator>
RenderPassIdAllocatorMap;
RenderPassIdAllocatorMap render_pass_allocator_map_;
// The following state is only valid for the duration of one Aggregate call
// and is only stored on the class to avoid having to pass through every
// function call.
// This is the set of surfaces referenced in the aggregation so far, used to
// detect cycles.
std::set<int> referenced_surfaces_;
// This is the pass list for the aggregated frame.
RenderPassList* dest_pass_list_;
DISALLOW_COPY_AND_ASSIGN(SurfaceAggregator);
};
} // namespace cc
#endif // CC_SURFACES_SURFACE_AGGREGATOR_H_
// 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_test_helpers.h"
#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
#include "cc/layers/append_quads_data.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/delegated_frame_data.h"
#include "cc/quads/render_pass_draw_quad.h"
#include "cc/quads/shared_quad_state.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/surface_draw_quad.h"
#include "cc/surfaces/surface.h"
#include "cc/test/mock_quad_culler.h"
#include "cc/test/render_pass_test_common.h"
#include "cc/test/render_pass_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkXfermode.h"
namespace cc {
namespace test {
void AddTestSurfaceQuad(TestRenderPass* pass,
const gfx::Size& surface_size,
int surface_id) {
gfx::Transform content_to_target_transform;
gfx::Size content_bounds = surface_size;
gfx::Rect visible_content_rect = gfx::Rect(surface_size);
gfx::Rect clip_rect = gfx::Rect(surface_size);
bool is_clipped = false;
float opacity = 1.0;
SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode;
scoped_ptr<SharedQuadState> shared_quad_state = SharedQuadState::Create();
shared_quad_state->SetAll(content_to_target_transform,
content_bounds,
visible_content_rect,
clip_rect,
is_clipped,
opacity,
blend_mode);
pass->shared_quad_state_list.push_back(shared_quad_state.Pass());
scoped_ptr<SurfaceDrawQuad> surface_quad = SurfaceDrawQuad::Create();
gfx::Rect quad_rect = gfx::Rect(surface_size);
surface_quad->SetNew(
pass->shared_quad_state_list.back(), gfx::Rect(surface_size), surface_id);
pass->quad_list.push_back(surface_quad.PassAs<DrawQuad>());
}
void AddTestRenderPassQuad(TestRenderPass* pass,
RenderPass::Id render_pass_id) {
MockQuadCuller quad_sink(&pass->quad_list, &pass->shared_quad_state_list);
AppendQuadsData data(pass->id);
gfx::Rect output_rect = gfx::Rect(0, 0, 5, 5);
SharedQuadState* shared_state =
quad_sink.UseSharedQuadState(SharedQuadState::Create());
shared_state->SetAll(gfx::Transform(),
output_rect.size(),
output_rect,
output_rect,
false,
1,
SkXfermode::kSrcOver_Mode);
scoped_ptr<RenderPassDrawQuad> quad = RenderPassDrawQuad::Create();
quad->SetNew(shared_state,
output_rect,
render_pass_id,
false,
0,
output_rect,
gfx::RectF(),
FilterOperations(),
FilterOperations());
quad_sink.Append(quad.PassAs<DrawQuad>(), &data);
}
void AddQuadInPass(TestRenderPass* pass, Quad desc) {
switch (desc.material) {
case DrawQuad::SOLID_COLOR:
AddQuad(pass, gfx::Rect(0, 0, 5, 5), desc.color);
break;
case DrawQuad::SURFACE_CONTENT:
AddTestSurfaceQuad(pass, gfx::Size(5, 5), desc.surface_id);
break;
case DrawQuad::RENDER_PASS:
AddTestRenderPassQuad(pass, desc.render_pass_id);
break;
default:
NOTREACHED();
}
}
void AddPasses(RenderPassList* pass_list,
const gfx::Rect& output_rect,
Pass* passes,
size_t pass_count) {
gfx::Transform root_transform;
for (size_t i = 0; i < pass_count; ++i) {
Pass pass = passes[i];
TestRenderPass* test_pass =
AddRenderPass(pass_list, pass.id, output_rect, root_transform);
for (size_t j = 0; j < pass.quad_count; ++j) {
AddQuadInPass(test_pass, pass.quads[j]);
}
}
}
void TestQuadMatchesExpectations(Quad expected_quad, DrawQuad* quad) {
switch (expected_quad.material) {
case DrawQuad::SOLID_COLOR: {
ASSERT_EQ(DrawQuad::SOLID_COLOR, quad->material);
const SolidColorDrawQuad* solid_color_quad =
SolidColorDrawQuad::MaterialCast(quad);
EXPECT_EQ(expected_quad.color, solid_color_quad->color);
break;
}
default:
NOTREACHED();
break;
}
}
void TestPassMatchesExpectations(Pass expected_pass, RenderPass* pass) {
ASSERT_EQ(expected_pass.quad_count, pass->quad_list.size());
for (size_t i = 0u; i < pass->quad_list.size(); ++i) {
SCOPED_TRACE(base::StringPrintf("Quad number %" PRIuS, i));
TestQuadMatchesExpectations(expected_pass.quads[i], pass->quad_list.at(i));
}
}
void TestPassesMatchExpectations(Pass* expected_passes,
size_t expected_pass_count,
RenderPassList* passes) {
ASSERT_EQ(expected_pass_count, passes->size());
for (size_t i = 0; i < passes->size(); ++i) {
SCOPED_TRACE(base::StringPrintf("Pass number %" PRIuS, i));
RenderPass* pass = passes->at(i);
TestPassMatchesExpectations(expected_passes[i], pass);
}
}
void SubmitFrame(Pass* passes, size_t pass_count, Surface* surface) {
RenderPassList pass_list;
AddPasses(&pass_list, gfx::Rect(surface->size()), passes, pass_count);
scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
pass_list.swap(frame_data->render_pass_list);
scoped_ptr<CompositorFrame> frame(new CompositorFrame);
frame->delegated_frame_data = frame_data.Pass();
surface->QueueFrame(frame.Pass());
}
} // namespace test
} // namespace cc
// 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.
#ifndef CC_SURFACES_SURFACE_AGGREGATOR_TEST_HELPERS_H_
#define CC_SURFACES_SURFACE_AGGREGATOR_TEST_HELPERS_H_
#include "cc/quads/draw_quad.h"
#include "cc/quads/render_pass.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/size.h"
namespace cc {
class Surface;
class TestRenderPass;
namespace test {
struct Quad {
static Quad SolidColorQuad(SkColor color) {
Quad quad;
quad.material = DrawQuad::SOLID_COLOR;
quad.color = color;
return quad;
}
static Quad SurfaceQuad(int surface_id) {
Quad quad;
quad.material = DrawQuad::SURFACE_CONTENT;
quad.surface_id = surface_id;
return quad;
}
static Quad RenderPassQuad(RenderPass::Id id) {
Quad quad;
quad.material = DrawQuad::RENDER_PASS;
quad.render_pass_id = id;
return quad;
}
DrawQuad::Material material;
// Set when material==DrawQuad::SURFACE_CONTENT.
int surface_id;
// Set when material==DrawQuad::SOLID_COLOR.
SkColor color;
// Set when material==DrawQuad::RENDER_PASS.
RenderPass::Id render_pass_id;
private:
Quad()
: material(DrawQuad::INVALID),
surface_id(-1),
color(SK_ColorWHITE),
render_pass_id(-1, -1) {}
};
struct Pass {
Pass(Quad* quads, size_t quad_count, RenderPass::Id id)
: quads(quads), quad_count(quad_count), id(id) {}
Pass(Quad* quads, size_t quad_count)
: quads(quads), quad_count(quad_count), id(1, 1) {}
Quad* quads;
size_t quad_count;
RenderPass::Id id;
};
void AddSurfaceQuad(TestRenderPass* pass,
const gfx::Size& surface_size,
int surface_id);
void AddQuadInPass(TestRenderPass* pass, Quad desc);
void AddPasses(RenderPassList* pass_list,
const gfx::Rect& output_rect,
Pass* passes,
size_t pass_count);
void TestQuadMatchesExpectations(Quad expected_quad, DrawQuad* quad);
void TestPassMatchesExpectations(Pass expected_pass, RenderPass* pass);
void TestPassesMatchExpectations(Pass* expected_passes,
size_t expected_pass_count,
RenderPassList* passes);
void SubmitFrame(Pass* passes, size_t pass_count, Surface* surface);
} // namespace test
} // namespace cc
#endif // CC_SURFACES_SURFACE_AGGREGATOR_TEST_HELPERS_H_
This diff is collapsed.
...@@ -26,4 +26,3 @@ TEST(SurfaceTest, SurfaceLifetime) { ...@@ -26,4 +26,3 @@ TEST(SurfaceTest, SurfaceLifetime) {
} // namespace } // namespace
} // namespace cc } // namespace cc
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment