texture_layer_impl.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
1// Copyright 2011 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/texture_layer_impl.h"
6
7#include <vector>
8
9#include "base/strings/stringprintf.h"
10#include "cc/layers/quad_sink.h"
11#include "cc/output/renderer.h"
12#include "cc/quads/texture_draw_quad.h"
13#include "cc/resources/platform_color.h"
14#include "cc/resources/scoped_resource.h"
15#include "cc/resources/single_release_callback.h"
16#include "cc/trees/layer_tree_impl.h"
17
18namespace cc {
19
20TextureLayerImpl::TextureLayerImpl(LayerTreeImpl* tree_impl,
21                                   int id,
22                                   bool uses_mailbox)
23    : LayerImpl(tree_impl, id),
24      texture_id_(0),
25      external_texture_resource_(0),
26      premultiplied_alpha_(true),
27      blend_background_color_(false),
28      flipped_(true),
29      uv_top_left_(0.f, 0.f),
30      uv_bottom_right_(1.f, 1.f),
31      uses_mailbox_(uses_mailbox),
32      own_mailbox_(false),
33      valid_texture_copy_(false) {
34  vertex_opacity_[0] = 1.0f;
35  vertex_opacity_[1] = 1.0f;
36  vertex_opacity_[2] = 1.0f;
37  vertex_opacity_[3] = 1.0f;
38}
39
40TextureLayerImpl::~TextureLayerImpl() { FreeTextureMailbox(); }
41
42void TextureLayerImpl::SetTextureMailbox(
43    const TextureMailbox& mailbox,
44    scoped_ptr<SingleReleaseCallback> release_callback) {
45  DCHECK(uses_mailbox_);
46  DCHECK_EQ(mailbox.IsValid(), !!release_callback);
47  FreeTextureMailbox();
48  texture_mailbox_ = mailbox;
49  release_callback_ = release_callback.Pass();
50  own_mailbox_ = true;
51  valid_texture_copy_ = false;
52}
53
54scoped_ptr<LayerImpl> TextureLayerImpl::CreateLayerImpl(
55    LayerTreeImpl* tree_impl) {
56  return TextureLayerImpl::Create(tree_impl, id(), uses_mailbox_).
57      PassAs<LayerImpl>();
58}
59
60void TextureLayerImpl::PushPropertiesTo(LayerImpl* layer) {
61  LayerImpl::PushPropertiesTo(layer);
62
63  TextureLayerImpl* texture_layer = static_cast<TextureLayerImpl*>(layer);
64  texture_layer->set_flipped(flipped_);
65  texture_layer->set_uv_top_left(uv_top_left_);
66  texture_layer->set_uv_bottom_right(uv_bottom_right_);
67  texture_layer->set_vertex_opacity(vertex_opacity_);
68  texture_layer->set_premultiplied_alpha(premultiplied_alpha_);
69  if (uses_mailbox_ && own_mailbox_) {
70    texture_layer->SetTextureMailbox(texture_mailbox_,
71                                     release_callback_.Pass());
72    own_mailbox_ = false;
73  } else {
74    texture_layer->set_texture_id(texture_id_);
75  }
76}
77
78bool TextureLayerImpl::WillDraw(DrawMode draw_mode,
79                                ResourceProvider* resource_provider) {
80  if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
81    return false;
82
83  if (uses_mailbox_) {
84    if (own_mailbox_) {
85      DCHECK(!external_texture_resource_);
86      if ((draw_mode == DRAW_MODE_HARDWARE && texture_mailbox_.IsTexture()) ||
87          (draw_mode == DRAW_MODE_SOFTWARE &&
88           texture_mailbox_.IsSharedMemory())) {
89        external_texture_resource_ =
90            resource_provider->CreateResourceFromTextureMailbox(
91                texture_mailbox_,
92                release_callback_.Pass());
93        DCHECK(external_texture_resource_);
94        texture_copy_.reset();
95        valid_texture_copy_ = false;
96      }
97      if (external_texture_resource_)
98        own_mailbox_ = false;
99    }
100
101    if (!valid_texture_copy_ && draw_mode == DRAW_MODE_HARDWARE &&
102        texture_mailbox_.IsSharedMemory()) {
103      DCHECK(!external_texture_resource_);
104      // Have to upload a copy to a texture for it to be used in a
105      // hardware draw.
106      if (!texture_copy_)
107        texture_copy_ = ScopedResource::create(resource_provider);
108      if (texture_copy_->size() != texture_mailbox_.shared_memory_size() ||
109          resource_provider->InUseByConsumer(texture_copy_->id()))
110        texture_copy_->Free();
111
112      if (!texture_copy_->id()) {
113        texture_copy_->Allocate(texture_mailbox_.shared_memory_size(),
114                                ResourceProvider::TextureUsageAny,
115                                resource_provider->best_texture_format());
116      }
117
118      if (texture_copy_->id()) {
119        std::vector<uint8> swizzled;
120        uint8* pixels =
121            static_cast<uint8*>(texture_mailbox_.shared_memory()->memory());
122
123        if (!PlatformColor::SameComponentOrder(texture_copy_->format())) {
124          // Swizzle colors. This is slow, but should be really uncommon.
125          swizzled.resize(texture_mailbox_.shared_memory_size_in_bytes());
126          for (size_t i = 0; i < texture_mailbox_.shared_memory_size_in_bytes();
127               i += 4) {
128            swizzled[i] = pixels[i + 2];
129            swizzled[i + 1] = pixels[i + 1];
130            swizzled[i + 2] = pixels[i];
131            swizzled[i + 3] = pixels[i + 3];
132          }
133          pixels = &swizzled[0];
134        }
135
136        resource_provider->SetPixels(
137            texture_copy_->id(),
138            pixels,
139            gfx::Rect(texture_mailbox_.shared_memory_size()),
140            gfx::Rect(texture_mailbox_.shared_memory_size()),
141            gfx::Vector2d());
142
143        valid_texture_copy_ = true;
144      }
145    }
146  } else if (texture_id_) {
147    DCHECK(!external_texture_resource_);
148    if (draw_mode == DRAW_MODE_HARDWARE) {
149      external_texture_resource_ =
150          resource_provider->CreateResourceFromExternalTexture(
151              GL_TEXTURE_2D,
152              texture_id_);
153    }
154  }
155  return (external_texture_resource_ || valid_texture_copy_) &&
156         LayerImpl::WillDraw(draw_mode, resource_provider);
157}
158
159void TextureLayerImpl::AppendQuads(QuadSink* quad_sink,
160                                   AppendQuadsData* append_quads_data) {
161  DCHECK(external_texture_resource_ || valid_texture_copy_);
162
163  SharedQuadState* shared_quad_state =
164      quad_sink->UseSharedQuadState(CreateSharedQuadState());
165  AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
166
167  SkColor bg_color = blend_background_color_ ?
168      background_color() : SK_ColorTRANSPARENT;
169  bool opaque = contents_opaque() || (SkColorGetA(bg_color) == 0xFF);
170
171  gfx::Rect quad_rect(content_bounds());
172  gfx::Rect opaque_rect = opaque ? quad_rect : gfx::Rect();
173  scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
174  ResourceProvider::ResourceId id =
175      valid_texture_copy_ ? texture_copy_->id() : external_texture_resource_;
176  quad->SetNew(shared_quad_state,
177               quad_rect,
178               opaque_rect,
179               id,
180               premultiplied_alpha_,
181               uv_top_left_,
182               uv_bottom_right_,
183               bg_color,
184               vertex_opacity_,
185               flipped_);
186
187  // Perform explicit clipping on a quad to avoid setting a scissor later.
188  if (shared_quad_state->is_clipped && quad->PerformClipping())
189    shared_quad_state->is_clipped = false;
190  if (!quad->rect.IsEmpty())
191    quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
192}
193
194void TextureLayerImpl::DidDraw(ResourceProvider* resource_provider) {
195  LayerImpl::DidDraw(resource_provider);
196  if (uses_mailbox_ || !external_texture_resource_)
197    return;
198  // TODO(danakj): the following assert will not be true when sending resources
199  // to a parent compositor. A synchronization scheme (double-buffering or
200  // pipelining of updates) for the client will need to exist to solve this.
201  DCHECK(!resource_provider->InUseByConsumer(external_texture_resource_));
202  resource_provider->DeleteResource(external_texture_resource_);
203  external_texture_resource_ = 0;
204}
205
206Region TextureLayerImpl::VisibleContentOpaqueRegion() const {
207  if (contents_opaque())
208    return visible_content_rect();
209
210  if (blend_background_color_ && (SkColorGetA(background_color()) == 0xFF))
211    return visible_content_rect();
212
213  return Region();
214}
215
216void TextureLayerImpl::DidLoseOutputSurface() {
217  if (external_texture_resource_ && !uses_mailbox_) {
218    ResourceProvider* resource_provider =
219        layer_tree_impl()->resource_provider();
220    resource_provider->DeleteResource(external_texture_resource_);
221  }
222  texture_copy_.reset();
223  texture_id_ = 0;
224  external_texture_resource_ = 0;
225  valid_texture_copy_ = false;
226}
227
228const char* TextureLayerImpl::LayerTypeAsString() const {
229  return "cc::TextureLayerImpl";
230}
231
232bool TextureLayerImpl::CanClipSelf() const {
233  return true;
234}
235
236void TextureLayerImpl::FreeTextureMailbox() {
237  if (!uses_mailbox_)
238    return;
239  if (own_mailbox_) {
240    DCHECK(!external_texture_resource_);
241    if (release_callback_)
242      release_callback_->Run(texture_mailbox_.sync_point(), false);
243    texture_mailbox_ = TextureMailbox();
244    release_callback_.reset();
245  } else if (external_texture_resource_) {
246    DCHECK(!own_mailbox_);
247    ResourceProvider* resource_provider =
248        layer_tree_impl()->resource_provider();
249    resource_provider->DeleteResource(external_texture_resource_);
250    external_texture_resource_ = 0;
251  }
252}
253
254}  // namespace cc
255