delegated_renderer_layer_impl.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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    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.
146  RenderPass* new_root_pass = render_pass_list.back();
147  gfx::Size frame_size = new_root_pass->output_rect.size();
148  gfx::RectF damage_in_layer = MathUtil::MapClippedRect(
149      DelegatedFrameToLayerSpaceTransform(frame_size), damage_in_frame);
150  set_update_rect(gfx::UnionRects(update_rect(), damage_in_layer));
151
152  SetRenderPasses(&render_pass_list);
153  have_render_passes_to_push_ = true;
154}
155
156void DelegatedRendererLayerImpl::SetDisplaySize(gfx::Size size) {
157  if (display_size_ == size)
158    return;
159  display_size_ = size;
160  NoteLayerPropertyChanged();
161}
162
163void DelegatedRendererLayerImpl::SetRenderPasses(
164    ScopedPtrVector<RenderPass>* render_passes_in_draw_order) {
165  ClearRenderPasses();
166
167  for (size_t i = 0; i < render_passes_in_draw_order->size(); ++i) {
168    ScopedPtrVector<RenderPass>::iterator to_take =
169        render_passes_in_draw_order->begin() + i;
170    render_passes_index_by_id_.insert(
171        std::pair<RenderPass::Id, int>((*to_take)->id, i));
172    scoped_ptr<RenderPass> taken_render_pass =
173        render_passes_in_draw_order->take(to_take);
174    render_passes_in_draw_order_.push_back(taken_render_pass.Pass());
175  }
176
177  // Give back an empty array instead of nulls.
178  render_passes_in_draw_order->clear();
179}
180
181void DelegatedRendererLayerImpl::ClearRenderPasses() {
182  render_passes_index_by_id_.clear();
183  render_passes_in_draw_order_.clear();
184}
185
186scoped_ptr<LayerImpl> DelegatedRendererLayerImpl::CreateLayerImpl(
187    LayerTreeImpl* tree_impl) {
188  return DelegatedRendererLayerImpl::Create(
189      tree_impl, id()).PassAs<LayerImpl>();
190}
191
192void DelegatedRendererLayerImpl::DidLoseOutputSurface() {
193  ClearRenderPasses();
194  ClearChildId();
195}
196
197gfx::Transform DelegatedRendererLayerImpl::DelegatedFrameToLayerSpaceTransform(
198    gfx::Size frame_size) const {
199  gfx::Size display_size = display_size_.IsEmpty() ? bounds() : display_size_;
200
201  gfx::Transform delegated_frame_to_layer_space_transform;
202  delegated_frame_to_layer_space_transform.Scale(
203      static_cast<double>(display_size.width()) / frame_size.width(),
204      static_cast<double>(display_size.height()) / frame_size.height());
205  return delegated_frame_to_layer_space_transform;
206}
207
208static inline int IndexToId(int index) { return index + 1; }
209static inline int IdToIndex(int id) { return id - 1; }
210
211RenderPass::Id DelegatedRendererLayerImpl::FirstContributingRenderPassId()
212    const {
213  return RenderPass::Id(id(), IndexToId(0));
214}
215
216RenderPass::Id DelegatedRendererLayerImpl::NextContributingRenderPassId(
217    RenderPass::Id previous) const {
218  return RenderPass::Id(previous.layer_id, previous.index + 1);
219}
220
221bool DelegatedRendererLayerImpl::ConvertDelegatedRenderPassId(
222    RenderPass::Id delegated_render_pass_id,
223    RenderPass::Id* output_render_pass_id) const {
224  base::hash_map<RenderPass::Id, int>::const_iterator found =
225      render_passes_index_by_id_.find(delegated_render_pass_id);
226  if (found == render_passes_index_by_id_.end()) {
227    // Be robust against a RenderPass id that isn't part of the frame.
228    return false;
229  }
230  unsigned delegated_render_pass_index = found->second;
231  *output_render_pass_id =
232      RenderPass::Id(id(), IndexToId(delegated_render_pass_index));
233  return true;
234}
235
236void DelegatedRendererLayerImpl::AppendContributingRenderPasses(
237    RenderPassSink* render_pass_sink) {
238  DCHECK(HasContributingDelegatedRenderPasses());
239
240  const RenderPass* root_delegated_render_pass =
241      render_passes_in_draw_order_.back();
242  gfx::Size frame_size = root_delegated_render_pass->output_rect.size();
243  gfx::Transform delegated_frame_to_root_transform =
244      screen_space_transform() *
245      DelegatedFrameToLayerSpaceTransform(frame_size);
246
247  for (size_t i = 0; i < render_passes_in_draw_order_.size() - 1; ++i) {
248    RenderPass::Id output_render_pass_id(-1, -1);
249    bool present =
250        ConvertDelegatedRenderPassId(render_passes_in_draw_order_[i]->id,
251                                     &output_render_pass_id);
252
253    // Don't clash with the RenderPass we generate if we own a RenderSurface.
254    DCHECK(present) << render_passes_in_draw_order_[i]->id.layer_id << ", "
255                    << render_passes_in_draw_order_[i]->id.index;
256    DCHECK_GT(output_render_pass_id.index, 0);
257
258    scoped_ptr<RenderPass> copy_pass =
259        render_passes_in_draw_order_[i]->Copy(output_render_pass_id);
260    copy_pass->transform_to_root_target.ConcatTransform(
261        delegated_frame_to_root_transform);
262    render_pass_sink->AppendRenderPass(copy_pass.Pass());
263  }
264}
265
266bool DelegatedRendererLayerImpl::WillDraw(DrawMode draw_mode,
267                                          ResourceProvider* resource_provider) {
268  if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
269    return false;
270  return LayerImpl::WillDraw(draw_mode, resource_provider);
271}
272
273void DelegatedRendererLayerImpl::AppendQuads(
274    QuadSink* quad_sink,
275    AppendQuadsData* append_quads_data) {
276  AppendRainbowDebugBorder(quad_sink, append_quads_data);
277
278  // This list will be empty after a lost context until a new frame arrives.
279  if (render_passes_in_draw_order_.empty())
280    return;
281
282  RenderPass::Id target_render_pass_id = append_quads_data->render_pass_id;
283
284  const RenderPass* root_delegated_render_pass =
285      render_passes_in_draw_order_.back();
286
287  DCHECK(root_delegated_render_pass->output_rect.origin().IsOrigin());
288  gfx::Size frame_size = root_delegated_render_pass->output_rect.size();
289
290  // If the index of the RenderPassId is 0, then it is a RenderPass generated
291  // for a layer in this compositor, not the delegating renderer. Then we want
292  // to merge our root RenderPass with the target RenderPass. Otherwise, it is
293  // some RenderPass which we added from the delegating renderer.
294  bool should_merge_root_render_pass_with_target = !target_render_pass_id.index;
295  if (should_merge_root_render_pass_with_target) {
296    // Verify that the RenderPass we are appending to is created by our
297    // render_target.
298    DCHECK(target_render_pass_id.layer_id == render_target()->id());
299
300    AppendRenderPassQuads(
301        quad_sink, append_quads_data, root_delegated_render_pass, frame_size);
302  } else {
303    // Verify that the RenderPass we are appending to was created by us.
304    DCHECK(target_render_pass_id.layer_id == id());
305
306    int render_pass_index = IdToIndex(target_render_pass_id.index);
307    const RenderPass* delegated_render_pass =
308        render_passes_in_draw_order_[render_pass_index];
309    AppendRenderPassQuads(
310        quad_sink, append_quads_data, delegated_render_pass, frame_size);
311  }
312}
313
314void DelegatedRendererLayerImpl::AppendRainbowDebugBorder(
315    QuadSink* quad_sink,
316    AppendQuadsData* append_quads_data) {
317  if (!ShowDebugBorders())
318    return;
319
320  SharedQuadState* shared_quad_state =
321      quad_sink->UseSharedQuadState(CreateSharedQuadState());
322
323  SkColor color;
324  float border_width;
325  GetDebugBorderProperties(&color, &border_width);
326
327  SkColor colors[] = {
328    0x80ff0000,  // Red.
329    0x80ffa500,  // Orange.
330    0x80ffff00,  // Yellow.
331    0x80008000,  // Green.
332    0x800000ff,  // Blue.
333    0x80ee82ee,  // Violet.
334  };
335  const int kNumColors = arraysize(colors);
336
337  const int kStripeWidth = 300;
338  const int kStripeHeight = 300;
339
340  for (size_t i = 0; ; ++i) {
341    // For horizontal lines.
342    int x =  kStripeWidth * i;
343    int width = std::min(kStripeWidth, content_bounds().width() - x - 1);
344
345    // For vertical lines.
346    int y = kStripeHeight * i;
347    int height = std::min(kStripeHeight, content_bounds().height() - y - 1);
348
349    gfx::Rect top(x, 0, width, border_width);
350    gfx::Rect bottom(x,
351                     content_bounds().height() - border_width,
352                     width,
353                     border_width);
354    gfx::Rect left(0, y, border_width, height);
355    gfx::Rect right(content_bounds().width() - border_width,
356                    y,
357                    border_width,
358                    height);
359
360    if (top.IsEmpty() && left.IsEmpty())
361      break;
362
363    if (!top.IsEmpty()) {
364      scoped_ptr<SolidColorDrawQuad> top_quad = SolidColorDrawQuad::Create();
365      top_quad->SetNew(shared_quad_state, top, colors[i % kNumColors], false);
366      quad_sink->Append(top_quad.PassAs<DrawQuad>(), append_quads_data);
367
368      scoped_ptr<SolidColorDrawQuad> bottom_quad = SolidColorDrawQuad::Create();
369      bottom_quad->SetNew(shared_quad_state,
370                          bottom,
371                          colors[kNumColors - 1 - (i % kNumColors)],
372                          false);
373      quad_sink->Append(bottom_quad.PassAs<DrawQuad>(), append_quads_data);
374    }
375    if (!left.IsEmpty()) {
376      scoped_ptr<SolidColorDrawQuad> left_quad = SolidColorDrawQuad::Create();
377      left_quad->SetNew(shared_quad_state,
378                        left,
379                        colors[kNumColors - 1 - (i % kNumColors)],
380                        false);
381      quad_sink->Append(left_quad.PassAs<DrawQuad>(), append_quads_data);
382
383      scoped_ptr<SolidColorDrawQuad> right_quad = SolidColorDrawQuad::Create();
384      right_quad->SetNew(
385          shared_quad_state, right, colors[i % kNumColors], false);
386      quad_sink->Append(right_quad.PassAs<DrawQuad>(), append_quads_data);
387    }
388  }
389}
390
391void DelegatedRendererLayerImpl::AppendRenderPassQuads(
392    QuadSink* quad_sink,
393    AppendQuadsData* append_quads_data,
394    const RenderPass* delegated_render_pass,
395    gfx::Size frame_size) const {
396
397  const SharedQuadState* delegated_shared_quad_state = NULL;
398  SharedQuadState* output_shared_quad_state = NULL;
399
400  for (size_t i = 0; i < delegated_render_pass->quad_list.size(); ++i) {
401    const DrawQuad* delegated_quad = delegated_render_pass->quad_list[i];
402
403    if (delegated_quad->shared_quad_state != delegated_shared_quad_state) {
404      delegated_shared_quad_state = delegated_quad->shared_quad_state;
405      output_shared_quad_state = quad_sink->UseSharedQuadState(
406          delegated_shared_quad_state->Copy());
407
408      bool is_root_delegated_render_pass =
409          delegated_render_pass == render_passes_in_draw_order_.back();
410      if (is_root_delegated_render_pass) {
411        // Don't allow areas inside the bounds that are empty.
412        DCHECK(display_size_.IsEmpty() ||
413               gfx::Rect(display_size_).Contains(gfx::Rect(bounds())));
414        gfx::Transform delegated_frame_to_target_transform =
415            draw_transform() * DelegatedFrameToLayerSpaceTransform(frame_size);
416
417        output_shared_quad_state->content_to_target_transform.ConcatTransform(
418            delegated_frame_to_target_transform);
419
420        if (render_target() == this) {
421          DCHECK(!is_clipped());
422          DCHECK(render_surface());
423          DCHECK_EQ(0, num_unclipped_descendants());
424          output_shared_quad_state->clip_rect = MathUtil::MapClippedRect(
425              delegated_frame_to_target_transform,
426              output_shared_quad_state->clip_rect);
427        } else {
428          gfx::Rect clip_rect = drawable_content_rect();
429          if (output_shared_quad_state->is_clipped) {
430            clip_rect.Intersect(MathUtil::MapClippedRect(
431                delegated_frame_to_target_transform,
432                output_shared_quad_state->clip_rect));
433          }
434          output_shared_quad_state->clip_rect = clip_rect;
435          output_shared_quad_state->is_clipped = true;
436        }
437
438        output_shared_quad_state->opacity *= draw_opacity();
439      }
440    }
441    DCHECK(output_shared_quad_state);
442
443    scoped_ptr<DrawQuad> output_quad;
444    if (delegated_quad->material != DrawQuad::RENDER_PASS) {
445      output_quad = delegated_quad->Copy(output_shared_quad_state);
446    } else {
447      RenderPass::Id delegated_contributing_render_pass_id =
448          RenderPassDrawQuad::MaterialCast(delegated_quad)->render_pass_id;
449      RenderPass::Id output_contributing_render_pass_id(-1, -1);
450
451      bool present =
452          ConvertDelegatedRenderPassId(delegated_contributing_render_pass_id,
453                                       &output_contributing_render_pass_id);
454
455      // The frame may have a RenderPassDrawQuad that points to a RenderPass not
456      // part of the frame. Just ignore these quads.
457      if (present) {
458        DCHECK(output_contributing_render_pass_id !=
459               append_quads_data->render_pass_id);
460
461        output_quad = RenderPassDrawQuad::MaterialCast(delegated_quad)->Copy(
462            output_shared_quad_state,
463            output_contributing_render_pass_id).PassAs<DrawQuad>();
464      }
465    }
466
467    if (output_quad)
468      quad_sink->Append(output_quad.Pass(), append_quads_data);
469  }
470}
471
472const char* DelegatedRendererLayerImpl::LayerTypeAsString() const {
473  return "cc::DelegatedRendererLayerImpl";
474}
475
476void DelegatedRendererLayerImpl::ClearChildId() {
477  if (!child_id_)
478    return;
479
480  if (own_child_id_) {
481    ResourceProvider* provider = layer_tree_impl()->resource_provider();
482    provider->DestroyChild(child_id_);
483  }
484
485  child_id_ = 0;
486}
487
488}  // namespace cc
489