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