delegated_renderer_layer_impl.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
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/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
258void DelegatedRendererLayerImpl::AppendQuads(
259    QuadSink* quad_sink,
260    AppendQuadsData* append_quads_data) {
261  AppendRainbowDebugBorder(quad_sink, append_quads_data);
262
263  if (render_passes_in_draw_order_.empty())
264    return;
265
266  RenderPass::Id target_render_pass_id = append_quads_data->render_pass_id;
267
268  const RenderPass* root_delegated_render_pass =
269      render_passes_in_draw_order_.back();
270
271  DCHECK(root_delegated_render_pass->output_rect.origin().IsOrigin());
272  gfx::Size frame_size = root_delegated_render_pass->output_rect.size();
273
274  // If the index of the EenderPassId is 0, then it is a RenderPass generated
275  // for a layer in this compositor, not the delegated renderer. Then we want to
276  // merge our root RenderPass with the target RenderPass. Otherwise, it is some
277  // RenderPass which we added from the delegated renderer.
278  bool should_merge_root_render_pass_with_target = !target_render_pass_id.index;
279  if (should_merge_root_render_pass_with_target) {
280    // Verify that the RenderPass we are appending to is created our
281    // render_target.
282    DCHECK(target_render_pass_id.layer_id == render_target()->id());
283
284    AppendRenderPassQuads(
285        quad_sink, append_quads_data, root_delegated_render_pass, frame_size);
286  } else {
287    // Verify that the RenderPass we are appending to was created by us.
288    DCHECK(target_render_pass_id.layer_id == id());
289
290    int render_pass_index = IdToIndex(target_render_pass_id.index);
291    const RenderPass* delegated_render_pass =
292        render_passes_in_draw_order_[render_pass_index];
293    AppendRenderPassQuads(
294        quad_sink, append_quads_data, delegated_render_pass, frame_size);
295  }
296}
297
298void DelegatedRendererLayerImpl::AppendRainbowDebugBorder(
299    QuadSink* quad_sink,
300    AppendQuadsData* append_quads_data) {
301  if (!ShowDebugBorders())
302    return;
303
304  SharedQuadState* shared_quad_state =
305      quad_sink->UseSharedQuadState(CreateSharedQuadState());
306
307  SkColor color;
308  float border_width;
309  GetDebugBorderProperties(&color, &border_width);
310
311  SkColor colors[] = {
312    0x80ff0000,  // Red.
313    0x80ffa500,  // Orange.
314    0x80ffff00,  // Yellow.
315    0x80008000,  // Green.
316    0x800000ff,  // Blue.
317    0x80ee82ee,  // Violet.
318  };
319  const int kNumColors = arraysize(colors);
320
321  const int kStripeWidth = 300;
322  const int kStripeHeight = 300;
323
324  for (size_t i = 0; ; ++i) {
325    // For horizontal lines.
326    int x =  kStripeWidth * i;
327    int width = std::min(kStripeWidth, content_bounds().width() - x - 1);
328
329    // For vertical lines.
330    int y = kStripeHeight * i;
331    int height = std::min(kStripeHeight, content_bounds().height() - y - 1);
332
333    gfx::Rect top(x, 0, width, border_width);
334    gfx::Rect bottom(x,
335                     content_bounds().height() - border_width,
336                     width,
337                     border_width);
338    gfx::Rect left(0, y, border_width, height);
339    gfx::Rect right(content_bounds().width() - border_width,
340                    y,
341                    border_width,
342                    height);
343
344    if (top.IsEmpty() && left.IsEmpty())
345      break;
346
347    if (!top.IsEmpty()) {
348      scoped_ptr<SolidColorDrawQuad> top_quad = SolidColorDrawQuad::Create();
349      top_quad->SetNew(shared_quad_state, top, colors[i % kNumColors], false);
350      quad_sink->Append(top_quad.PassAs<DrawQuad>(), append_quads_data);
351
352      scoped_ptr<SolidColorDrawQuad> bottom_quad = SolidColorDrawQuad::Create();
353      bottom_quad->SetNew(shared_quad_state,
354                          bottom,
355                          colors[kNumColors - 1 - (i % kNumColors)],
356                          false);
357      quad_sink->Append(bottom_quad.PassAs<DrawQuad>(), append_quads_data);
358    }
359    if (!left.IsEmpty()) {
360      scoped_ptr<SolidColorDrawQuad> left_quad = SolidColorDrawQuad::Create();
361      left_quad->SetNew(shared_quad_state,
362                        left,
363                        colors[kNumColors - 1 - (i % kNumColors)],
364                        false);
365      quad_sink->Append(left_quad.PassAs<DrawQuad>(), append_quads_data);
366
367      scoped_ptr<SolidColorDrawQuad> right_quad = SolidColorDrawQuad::Create();
368      right_quad->SetNew(
369          shared_quad_state, right, colors[i % kNumColors], false);
370      quad_sink->Append(right_quad.PassAs<DrawQuad>(), append_quads_data);
371    }
372  }
373}
374
375void DelegatedRendererLayerImpl::AppendRenderPassQuads(
376    QuadSink* quad_sink,
377    AppendQuadsData* append_quads_data,
378    const RenderPass* delegated_render_pass,
379    gfx::Size frame_size) const {
380
381  const SharedQuadState* delegated_shared_quad_state = NULL;
382  SharedQuadState* output_shared_quad_state = NULL;
383
384  for (size_t i = 0; i < delegated_render_pass->quad_list.size(); ++i) {
385    const DrawQuad* delegated_quad = delegated_render_pass->quad_list[i];
386
387    if (delegated_quad->shared_quad_state != delegated_shared_quad_state) {
388      delegated_shared_quad_state = delegated_quad->shared_quad_state;
389      output_shared_quad_state = quad_sink->UseSharedQuadState(
390          delegated_shared_quad_state->Copy());
391
392      bool is_root_delegated_render_pass =
393          delegated_render_pass == render_passes_in_draw_order_.back();
394      if (is_root_delegated_render_pass) {
395        // Don't allow areas inside the bounds that are empty.
396        DCHECK(display_size_.IsEmpty() ||
397               gfx::Rect(display_size_).Contains(gfx::Rect(bounds())));
398        gfx::Transform delegated_frame_to_target_transform =
399            draw_transform() * DelegatedFrameToLayerSpaceTransform(frame_size);
400
401        output_shared_quad_state->content_to_target_transform.ConcatTransform(
402            delegated_frame_to_target_transform);
403
404        if (render_target() == this) {
405          DCHECK(!is_clipped());
406          DCHECK(render_surface());
407          output_shared_quad_state->clip_rect = MathUtil::MapClippedRect(
408              delegated_frame_to_target_transform,
409              output_shared_quad_state->clip_rect);
410        } else {
411          gfx::Rect clip_rect = drawable_content_rect();
412          if (output_shared_quad_state->is_clipped) {
413            clip_rect.Intersect(MathUtil::MapClippedRect(
414                delegated_frame_to_target_transform,
415                output_shared_quad_state->clip_rect));
416          }
417          output_shared_quad_state->clip_rect = clip_rect;
418          output_shared_quad_state->is_clipped = true;
419        }
420
421        output_shared_quad_state->opacity *= draw_opacity();
422      }
423    }
424    DCHECK(output_shared_quad_state);
425
426    scoped_ptr<DrawQuad> output_quad;
427    if (delegated_quad->material != DrawQuad::RENDER_PASS) {
428      output_quad = delegated_quad->Copy(output_shared_quad_state);
429    } else {
430      RenderPass::Id delegated_contributing_render_pass_id =
431          RenderPassDrawQuad::MaterialCast(delegated_quad)->render_pass_id;
432      RenderPass::Id output_contributing_render_pass_id =
433          ConvertDelegatedRenderPassId(delegated_contributing_render_pass_id);
434      DCHECK(output_contributing_render_pass_id !=
435             append_quads_data->render_pass_id);
436
437      output_quad = RenderPassDrawQuad::MaterialCast(delegated_quad)->Copy(
438          output_shared_quad_state,
439          output_contributing_render_pass_id).PassAs<DrawQuad>();
440    }
441    DCHECK(output_quad.get());
442
443    quad_sink->Append(output_quad.Pass(), append_quads_data);
444  }
445}
446
447const char* DelegatedRendererLayerImpl::LayerTypeAsString() const {
448  return "cc::DelegatedRendererLayerImpl";
449}
450
451void DelegatedRendererLayerImpl::CreateChildIdIfNeeded() {
452  if (child_id_)
453    return;
454
455  ResourceProvider* resource_provider = layer_tree_impl()->resource_provider();
456  child_id_ = resource_provider->CreateChild();
457  own_child_id_ = true;
458}
459
460void DelegatedRendererLayerImpl::ClearChildId() {
461  if (!child_id_)
462    return;
463
464  if (own_child_id_) {
465    ResourceProvider* provider = layer_tree_impl()->resource_provider();
466    provider->DestroyChild(child_id_);
467  }
468
469  child_id_ = 0;
470}
471
472}  // namespace cc
473