delegated_renderer_layer_impl.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
1// Copyright 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "cc/layers/delegated_renderer_layer_impl.h"
6
7#include <algorithm>
8#include <utility>
9
10#include "base/bind.h"
11#include "base/containers/hash_tables.h"
12#include "cc/base/math_util.h"
13#include "cc/layers/append_quads_data.h"
14#include "cc/layers/quad_sink.h"
15#include "cc/layers/render_pass_sink.h"
16#include "cc/output/delegated_frame_data.h"
17#include "cc/quads/render_pass_draw_quad.h"
18#include "cc/quads/solid_color_draw_quad.h"
19#include "cc/trees/layer_tree_impl.h"
20
21namespace cc {
22
23DelegatedRendererLayerImpl::DelegatedRendererLayerImpl(
24    LayerTreeImpl* tree_impl, int id)
25    : LayerImpl(tree_impl, id),
26      have_render_passes_to_push_(false),
27      child_id_(0),
28      own_child_id_(false) {
29}
30
31DelegatedRendererLayerImpl::~DelegatedRendererLayerImpl() {
32  ClearRenderPasses();
33  ClearChildId();
34}
35
36bool DelegatedRendererLayerImpl::HasDelegatedContent() const { return true; }
37
38bool DelegatedRendererLayerImpl::HasContributingDelegatedRenderPasses() const {
39  // The root RenderPass for the layer is merged with its target
40  // RenderPass in each frame. So we only have extra RenderPasses
41  // to merge when we have a non-root RenderPass present.
42  return render_passes_in_draw_order_.size() > 1;
43}
44
45static ResourceProvider::ResourceId ResourceRemapHelper(
46    bool* invalid_frame,
47    const ResourceProvider::ResourceIdMap& child_to_parent_map,
48    ResourceProvider::ResourceIdArray* resources_in_frame,
49    ResourceProvider::ResourceId id) {
50
51  ResourceProvider::ResourceIdMap::const_iterator it =
52      child_to_parent_map.find(id);
53  if (it == child_to_parent_map.end()) {
54    *invalid_frame = true;
55    return 0;
56  }
57
58  DCHECK_EQ(it->first, id);
59  ResourceProvider::ResourceId remapped_id = it->second;
60  resources_in_frame->push_back(id);
61  return remapped_id;
62}
63
64void DelegatedRendererLayerImpl::PushPropertiesTo(LayerImpl* layer) {
65  LayerImpl::PushPropertiesTo(layer);
66
67  DelegatedRendererLayerImpl* delegated_layer =
68      static_cast<DelegatedRendererLayerImpl*>(layer);
69
70  // If we have a new child_id to give to the active layer, it should
71  // have already deleted its old child_id.
72  DCHECK(delegated_layer->child_id_ == 0 ||
73         delegated_layer->child_id_ == child_id_);
74  delegated_layer->child_id_ = child_id_;
75  delegated_layer->own_child_id_ = true;
76  own_child_id_ = false;
77
78  delegated_layer->SetDisplaySize(display_size_);
79  if (have_render_passes_to_push_) {
80    // This passes ownership of the render passes to the active tree.
81    delegated_layer->SetRenderPasses(&render_passes_in_draw_order_);
82    DCHECK(render_passes_in_draw_order_.empty());
83    have_render_passes_to_push_ = false;
84  }
85
86  // This is just a copy for testing, since resources are added to the
87  // ResourceProvider in the pending tree.
88  delegated_layer->resources_ = resources_;
89}
90
91void DelegatedRendererLayerImpl::CreateChildIdIfNeeded(
92    const ReturnCallback& return_callback) {
93  if (child_id_)
94    return;
95
96  ResourceProvider* resource_provider = layer_tree_impl()->resource_provider();
97  child_id_ = resource_provider->CreateChild(return_callback);
98  own_child_id_ = true;
99}
100
101void DelegatedRendererLayerImpl::SetFrameData(
102    const DelegatedFrameData* frame_data,
103    const gfx::RectF& damage_in_frame) {
104  DCHECK(child_id_) << "CreateChildIdIfNeeded must be called first.";
105  DCHECK(frame_data);
106  DCHECK(!frame_data->render_pass_list.empty());
107  // A frame with an empty root render pass is invalid.
108  DCHECK(!frame_data->render_pass_list.back()->output_rect.IsEmpty());
109
110  ResourceProvider* resource_provider = layer_tree_impl()->resource_provider();
111    const ResourceProvider::ResourceIdMap& resource_map =
112        resource_provider->GetChildToParentMap(child_id_);
113
114  resource_provider->ReceiveFromChild(child_id_, frame_data->resource_list);
115
116  ScopedPtrVector<RenderPass> render_pass_list;
117  RenderPass::CopyAll(frame_data->render_pass_list, &render_pass_list);
118
119  bool invalid_frame = false;
120  ResourceProvider::ResourceIdArray resources_in_frame;
121  DrawQuad::ResourceIteratorCallback remap_resources_to_parent_callback =
122      base::Bind(&ResourceRemapHelper,
123                 &invalid_frame,
124                 resource_map,
125                 &resources_in_frame);
126  for (size_t i = 0; i < render_pass_list.size(); ++i) {
127    RenderPass* pass = render_pass_list[i];
128    for (size_t j = 0; j < pass->quad_list.size(); ++j) {
129      DrawQuad* quad = pass->quad_list[j];
130      quad->IterateResources(remap_resources_to_parent_callback);
131    }
132  }
133
134  if (invalid_frame) {
135    // Declare we are still using the last frame's resources.
136    resource_provider->DeclareUsedResourcesFromChild(child_id_, resources_);
137    return;
138  }
139
140  // Declare we are using the new frame's resources.
141  resources_.swap(resources_in_frame);
142  resource_provider->DeclareUsedResourcesFromChild(child_id_, resources_);
143
144  // Display size is already set so we can compute what the damage rect
145  // will be in layer space. The damage may exceed the visible portion of
146  // the frame, so intersect the damage to the layer's bounds.
147  RenderPass* new_root_pass = render_pass_list.back();
148  gfx::Size frame_size = new_root_pass->output_rect.size();
149  gfx::RectF damage_in_layer = MathUtil::MapClippedRect(
150      DelegatedFrameToLayerSpaceTransform(frame_size), damage_in_frame);
151  SetUpdateRect(gfx::IntersectRects(
152      gfx::UnionRects(update_rect(), damage_in_layer), gfx::Rect(bounds())));
153
154  SetRenderPasses(&render_pass_list);
155  have_render_passes_to_push_ = true;
156}
157
158void DelegatedRendererLayerImpl::SetDisplaySize(const gfx::Size& size) {
159  if (display_size_ == size)
160    return;
161  display_size_ = size;
162  NoteLayerPropertyChanged();
163}
164
165void DelegatedRendererLayerImpl::SetRenderPasses(
166    ScopedPtrVector<RenderPass>* render_passes_in_draw_order) {
167  ClearRenderPasses();
168
169  for (size_t i = 0; i < render_passes_in_draw_order->size(); ++i) {
170    ScopedPtrVector<RenderPass>::iterator to_take =
171        render_passes_in_draw_order->begin() + i;
172    render_passes_index_by_id_.insert(
173        std::pair<RenderPass::Id, int>((*to_take)->id, i));
174    scoped_ptr<RenderPass> taken_render_pass =
175        render_passes_in_draw_order->take(to_take);
176    render_passes_in_draw_order_.push_back(taken_render_pass.Pass());
177  }
178
179  // Give back an empty array instead of nulls.
180  render_passes_in_draw_order->clear();
181}
182
183void DelegatedRendererLayerImpl::ClearRenderPasses() {
184  render_passes_index_by_id_.clear();
185  render_passes_in_draw_order_.clear();
186}
187
188scoped_ptr<LayerImpl> DelegatedRendererLayerImpl::CreateLayerImpl(
189    LayerTreeImpl* tree_impl) {
190  return DelegatedRendererLayerImpl::Create(
191      tree_impl, id()).PassAs<LayerImpl>();
192}
193
194void DelegatedRendererLayerImpl::ReleaseResources() {
195  ClearRenderPasses();
196  ClearChildId();
197}
198
199gfx::Transform DelegatedRendererLayerImpl::DelegatedFrameToLayerSpaceTransform(
200    const gfx::Size& frame_size) const {
201  gfx::Size display_size = display_size_.IsEmpty() ? bounds() : display_size_;
202
203  gfx::Transform delegated_frame_to_layer_space_transform;
204  delegated_frame_to_layer_space_transform.Scale(
205      static_cast<double>(display_size.width()) / frame_size.width(),
206      static_cast<double>(display_size.height()) / frame_size.height());
207  return delegated_frame_to_layer_space_transform;
208}
209
210static inline int IndexToId(int index) { return index + 1; }
211static inline int IdToIndex(int id) { return id - 1; }
212
213RenderPass::Id DelegatedRendererLayerImpl::FirstContributingRenderPassId()
214    const {
215  return RenderPass::Id(id(), IndexToId(0));
216}
217
218RenderPass::Id DelegatedRendererLayerImpl::NextContributingRenderPassId(
219    RenderPass::Id previous) const {
220  return RenderPass::Id(previous.layer_id, previous.index + 1);
221}
222
223bool DelegatedRendererLayerImpl::ConvertDelegatedRenderPassId(
224    RenderPass::Id delegated_render_pass_id,
225    RenderPass::Id* output_render_pass_id) const {
226  base::hash_map<RenderPass::Id, int>::const_iterator found =
227      render_passes_index_by_id_.find(delegated_render_pass_id);
228  if (found == render_passes_index_by_id_.end()) {
229    // Be robust against a RenderPass id that isn't part of the frame.
230    return false;
231  }
232  unsigned delegated_render_pass_index = found->second;
233  *output_render_pass_id =
234      RenderPass::Id(id(), IndexToId(delegated_render_pass_index));
235  return true;
236}
237
238void DelegatedRendererLayerImpl::AppendContributingRenderPasses(
239    RenderPassSink* render_pass_sink) {
240  DCHECK(HasContributingDelegatedRenderPasses());
241
242  const RenderPass* root_delegated_render_pass =
243      render_passes_in_draw_order_.back();
244  gfx::Size frame_size = root_delegated_render_pass->output_rect.size();
245  gfx::Transform delegated_frame_to_root_transform =
246      screen_space_transform() *
247      DelegatedFrameToLayerSpaceTransform(frame_size);
248
249  for (size_t i = 0; i < render_passes_in_draw_order_.size() - 1; ++i) {
250    RenderPass::Id output_render_pass_id(-1, -1);
251    bool present =
252        ConvertDelegatedRenderPassId(render_passes_in_draw_order_[i]->id,
253                                     &output_render_pass_id);
254
255    // Don't clash with the RenderPass we generate if we own a RenderSurface.
256    DCHECK(present) << render_passes_in_draw_order_[i]->id.layer_id << ", "
257                    << render_passes_in_draw_order_[i]->id.index;
258    DCHECK_GT(output_render_pass_id.index, 0);
259
260    scoped_ptr<RenderPass> copy_pass =
261        render_passes_in_draw_order_[i]->Copy(output_render_pass_id);
262    copy_pass->transform_to_root_target.ConcatTransform(
263        delegated_frame_to_root_transform);
264    render_pass_sink->AppendRenderPass(copy_pass.Pass());
265  }
266}
267
268bool DelegatedRendererLayerImpl::WillDraw(DrawMode draw_mode,
269                                          ResourceProvider* resource_provider) {
270  if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
271    return false;
272  return LayerImpl::WillDraw(draw_mode, resource_provider);
273}
274
275void DelegatedRendererLayerImpl::AppendQuads(
276    QuadSink* quad_sink,
277    AppendQuadsData* append_quads_data) {
278  AppendRainbowDebugBorder(quad_sink, append_quads_data);
279
280  // This list will be empty after a lost context until a new frame arrives.
281  if (render_passes_in_draw_order_.empty())
282    return;
283
284  RenderPass::Id target_render_pass_id = append_quads_data->render_pass_id;
285
286  const RenderPass* root_delegated_render_pass =
287      render_passes_in_draw_order_.back();
288
289  DCHECK(root_delegated_render_pass->output_rect.origin().IsOrigin());
290  gfx::Size frame_size = root_delegated_render_pass->output_rect.size();
291
292  // If the index of the RenderPassId is 0, then it is a RenderPass generated
293  // for a layer in this compositor, not the delegating renderer. Then we want
294  // to merge our root RenderPass with the target RenderPass. Otherwise, it is
295  // some RenderPass which we added from the delegating renderer.
296  bool should_merge_root_render_pass_with_target = !target_render_pass_id.index;
297  if (should_merge_root_render_pass_with_target) {
298    // Verify that the RenderPass we are appending to is created by our
299    // render_target.
300    DCHECK(target_render_pass_id.layer_id == render_target()->id());
301
302    AppendRenderPassQuads(
303        quad_sink, append_quads_data, root_delegated_render_pass, frame_size);
304  } else {
305    // Verify that the RenderPass we are appending to was created by us.
306    DCHECK(target_render_pass_id.layer_id == id());
307
308    int render_pass_index = IdToIndex(target_render_pass_id.index);
309    const RenderPass* delegated_render_pass =
310        render_passes_in_draw_order_[render_pass_index];
311    AppendRenderPassQuads(
312        quad_sink, append_quads_data, delegated_render_pass, frame_size);
313  }
314}
315
316void DelegatedRendererLayerImpl::AppendRainbowDebugBorder(
317    QuadSink* quad_sink,
318    AppendQuadsData* append_quads_data) {
319  if (!ShowDebugBorders())
320    return;
321
322  SharedQuadState* shared_quad_state =
323      quad_sink->UseSharedQuadState(CreateSharedQuadState());
324
325  SkColor color;
326  float border_width;
327  GetDebugBorderProperties(&color, &border_width);
328
329  SkColor colors[] = {
330    0x80ff0000,  // Red.
331    0x80ffa500,  // Orange.
332    0x80ffff00,  // Yellow.
333    0x80008000,  // Green.
334    0x800000ff,  // Blue.
335    0x80ee82ee,  // Violet.
336  };
337  const int kNumColors = arraysize(colors);
338
339  const int kStripeWidth = 300;
340  const int kStripeHeight = 300;
341
342  for (size_t i = 0; ; ++i) {
343    // For horizontal lines.
344    int x =  kStripeWidth * i;
345    int width = std::min(kStripeWidth, content_bounds().width() - x - 1);
346
347    // For vertical lines.
348    int y = kStripeHeight * i;
349    int height = std::min(kStripeHeight, content_bounds().height() - y - 1);
350
351    gfx::Rect top(x, 0, width, border_width);
352    gfx::Rect bottom(x,
353                     content_bounds().height() - border_width,
354                     width,
355                     border_width);
356    gfx::Rect left(0, y, border_width, height);
357    gfx::Rect right(content_bounds().width() - border_width,
358                    y,
359                    border_width,
360                    height);
361
362    if (top.IsEmpty() && left.IsEmpty())
363      break;
364
365    if (!top.IsEmpty()) {
366      scoped_ptr<SolidColorDrawQuad> top_quad = SolidColorDrawQuad::Create();
367      top_quad->SetNew(
368          shared_quad_state, top, top, colors[i % kNumColors], false);
369      quad_sink->Append(top_quad.PassAs<DrawQuad>());
370
371      scoped_ptr<SolidColorDrawQuad> bottom_quad = SolidColorDrawQuad::Create();
372      bottom_quad->SetNew(shared_quad_state,
373                          bottom,
374                          bottom,
375                          colors[kNumColors - 1 - (i % kNumColors)],
376                          false);
377      quad_sink->Append(bottom_quad.PassAs<DrawQuad>());
378    }
379    if (!left.IsEmpty()) {
380      scoped_ptr<SolidColorDrawQuad> left_quad = SolidColorDrawQuad::Create();
381      left_quad->SetNew(shared_quad_state,
382                        left,
383                        left,
384                        colors[kNumColors - 1 - (i % kNumColors)],
385                        false);
386      quad_sink->Append(left_quad.PassAs<DrawQuad>());
387
388      scoped_ptr<SolidColorDrawQuad> right_quad = SolidColorDrawQuad::Create();
389      right_quad->SetNew(
390          shared_quad_state, right, right, colors[i % kNumColors], false);
391      quad_sink->Append(right_quad.PassAs<DrawQuad>());
392    }
393  }
394}
395
396void DelegatedRendererLayerImpl::AppendRenderPassQuads(
397    QuadSink* quad_sink,
398    AppendQuadsData* append_quads_data,
399    const RenderPass* delegated_render_pass,
400    const gfx::Size& frame_size) const {
401
402  const SharedQuadState* delegated_shared_quad_state = NULL;
403  SharedQuadState* output_shared_quad_state = NULL;
404
405  for (size_t i = 0; i < delegated_render_pass->quad_list.size(); ++i) {
406    const DrawQuad* delegated_quad = delegated_render_pass->quad_list[i];
407
408    if (delegated_quad->shared_quad_state != delegated_shared_quad_state) {
409      delegated_shared_quad_state = delegated_quad->shared_quad_state;
410      output_shared_quad_state = quad_sink->UseSharedQuadState(
411          delegated_shared_quad_state->Copy());
412
413      bool is_root_delegated_render_pass =
414          delegated_render_pass == render_passes_in_draw_order_.back();
415      if (is_root_delegated_render_pass) {
416        // Don't allow areas inside the bounds that are empty.
417        DCHECK(display_size_.IsEmpty() ||
418               gfx::Rect(display_size_).Contains(gfx::Rect(bounds())));
419        gfx::Transform delegated_frame_to_target_transform =
420            draw_transform() * DelegatedFrameToLayerSpaceTransform(frame_size);
421
422        output_shared_quad_state->content_to_target_transform.ConcatTransform(
423            delegated_frame_to_target_transform);
424
425        if (render_target() == this) {
426          DCHECK(!is_clipped());
427          DCHECK(render_surface());
428          DCHECK_EQ(0, num_unclipped_descendants());
429          output_shared_quad_state->clip_rect =
430              MathUtil::MapEnclosingClippedRect(
431                  delegated_frame_to_target_transform,
432                  output_shared_quad_state->clip_rect);
433        } else {
434          gfx::Rect clip_rect = drawable_content_rect();
435          if (output_shared_quad_state->is_clipped) {
436            clip_rect.Intersect(MathUtil::MapEnclosingClippedRect(
437                delegated_frame_to_target_transform,
438                output_shared_quad_state->clip_rect));
439          }
440          output_shared_quad_state->clip_rect = clip_rect;
441          output_shared_quad_state->is_clipped = true;
442        }
443
444        output_shared_quad_state->opacity *= draw_opacity();
445      }
446    }
447    DCHECK(output_shared_quad_state);
448
449    gfx::Rect quad_visible_rect = quad_sink->UnoccludedContentRect(
450        delegated_quad->visible_rect,
451        output_shared_quad_state->content_to_target_transform);
452    if (quad_visible_rect.IsEmpty())
453      continue;
454
455    scoped_ptr<DrawQuad> output_quad;
456    if (delegated_quad->material != DrawQuad::RENDER_PASS) {
457      output_quad = delegated_quad->Copy(output_shared_quad_state);
458      output_quad->visible_rect = quad_visible_rect;
459    } else {
460      RenderPass::Id delegated_contributing_render_pass_id =
461          RenderPassDrawQuad::MaterialCast(delegated_quad)->render_pass_id;
462      RenderPass::Id output_contributing_render_pass_id(-1, -1);
463
464      bool present =
465          ConvertDelegatedRenderPassId(delegated_contributing_render_pass_id,
466                                       &output_contributing_render_pass_id);
467
468      // The frame may have a RenderPassDrawQuad that points to a RenderPass not
469      // part of the frame. Just ignore these quads.
470      if (present) {
471        DCHECK(output_contributing_render_pass_id !=
472               append_quads_data->render_pass_id);
473
474        output_quad = RenderPassDrawQuad::MaterialCast(delegated_quad)->Copy(
475            output_shared_quad_state,
476            output_contributing_render_pass_id).PassAs<DrawQuad>();
477        output_quad->visible_rect = quad_visible_rect;
478      }
479    }
480
481    if (output_quad)
482      quad_sink->Append(output_quad.Pass());
483  }
484}
485
486const char* DelegatedRendererLayerImpl::LayerTypeAsString() const {
487  return "cc::DelegatedRendererLayerImpl";
488}
489
490void DelegatedRendererLayerImpl::ClearChildId() {
491  if (!child_id_)
492    return;
493
494  if (own_child_id_) {
495    ResourceProvider* provider = layer_tree_impl()->resource_provider();
496    provider->DestroyChild(child_id_);
497  }
498
499  resources_.clear();
500  child_id_ = 0;
501}
502
503}  // namespace cc
504