texture_layer_impl.cc revision f2477e01787aa58f445919b809d89e252beef54f
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  texture_layer->set_blend_background_color(blend_background_color_);
70  if (uses_mailbox_ && own_mailbox_) {
71    texture_layer->SetTextureMailbox(texture_mailbox_,
72                                     release_callback_.Pass());
73    own_mailbox_ = false;
74  } else {
75    texture_layer->set_texture_id(texture_id_);
76  }
77}
78
79bool TextureLayerImpl::WillDraw(DrawMode draw_mode,
80                                ResourceProvider* resource_provider) {
81  if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
82    return false;
83
84  if (uses_mailbox_) {
85    if (own_mailbox_) {
86      DCHECK(!external_texture_resource_);
87      if ((draw_mode == DRAW_MODE_HARDWARE && texture_mailbox_.IsTexture()) ||
88          (draw_mode == DRAW_MODE_SOFTWARE &&
89           texture_mailbox_.IsSharedMemory())) {
90        external_texture_resource_ =
91            resource_provider->CreateResourceFromTextureMailbox(
92                texture_mailbox_,
93                release_callback_.Pass());
94        DCHECK(external_texture_resource_);
95        texture_copy_.reset();
96        valid_texture_copy_ = false;
97      }
98      if (external_texture_resource_)
99        own_mailbox_ = false;
100    }
101
102    if (!valid_texture_copy_ && draw_mode == DRAW_MODE_HARDWARE &&
103        texture_mailbox_.IsSharedMemory()) {
104      DCHECK(!external_texture_resource_);
105      // Have to upload a copy to a texture for it to be used in a
106      // hardware draw.
107      if (!texture_copy_)
108        texture_copy_ = ScopedResource::create(resource_provider);
109      if (texture_copy_->size() != texture_mailbox_.shared_memory_size() ||
110          resource_provider->InUseByConsumer(texture_copy_->id()))
111        texture_copy_->Free();
112
113      if (!texture_copy_->id()) {
114        texture_copy_->Allocate(texture_mailbox_.shared_memory_size(),
115                                ResourceProvider::TextureUsageAny,
116                                resource_provider->best_texture_format());
117      }
118
119      if (texture_copy_->id()) {
120        std::vector<uint8> swizzled;
121        uint8* pixels =
122            static_cast<uint8*>(texture_mailbox_.shared_memory()->memory());
123
124        if (!PlatformColor::SameComponentOrder(texture_copy_->format())) {
125          // Swizzle colors. This is slow, but should be really uncommon.
126          swizzled.resize(texture_mailbox_.shared_memory_size_in_bytes());
127          for (size_t i = 0; i < texture_mailbox_.shared_memory_size_in_bytes();
128               i += 4) {
129            swizzled[i] = pixels[i + 2];
130            swizzled[i + 1] = pixels[i + 1];
131            swizzled[i + 2] = pixels[i];
132            swizzled[i + 3] = pixels[i + 3];
133          }
134          pixels = &swizzled[0];
135        }
136
137        resource_provider->SetPixels(
138            texture_copy_->id(),
139            pixels,
140            gfx::Rect(texture_mailbox_.shared_memory_size()),
141            gfx::Rect(texture_mailbox_.shared_memory_size()),
142            gfx::Vector2d());
143
144        valid_texture_copy_ = true;
145      }
146    }
147  } else if (texture_id_) {
148    DCHECK(!external_texture_resource_);
149    if (draw_mode == DRAW_MODE_HARDWARE) {
150      external_texture_resource_ =
151          resource_provider->CreateResourceFromExternalTexture(
152              GL_TEXTURE_2D,
153              texture_id_);
154    }
155  }
156  return (external_texture_resource_ || valid_texture_copy_) &&
157         LayerImpl::WillDraw(draw_mode, resource_provider);
158}
159
160void TextureLayerImpl::AppendQuads(QuadSink* quad_sink,
161                                   AppendQuadsData* append_quads_data) {
162  DCHECK(external_texture_resource_ || valid_texture_copy_);
163
164  SharedQuadState* shared_quad_state =
165      quad_sink->UseSharedQuadState(CreateSharedQuadState());
166  AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
167
168  SkColor bg_color = blend_background_color_ ?
169      background_color() : SK_ColorTRANSPARENT;
170  bool opaque = contents_opaque() || (SkColorGetA(bg_color) == 0xFF);
171
172  gfx::Rect quad_rect(content_bounds());
173  gfx::Rect opaque_rect = opaque ? quad_rect : gfx::Rect();
174  scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
175  ResourceProvider::ResourceId id =
176      valid_texture_copy_ ? texture_copy_->id() : external_texture_resource_;
177  quad->SetNew(shared_quad_state,
178               quad_rect,
179               opaque_rect,
180               id,
181               premultiplied_alpha_,
182               uv_top_left_,
183               uv_bottom_right_,
184               bg_color,
185               vertex_opacity_,
186               flipped_);
187  quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
188}
189
190void TextureLayerImpl::DidDraw(ResourceProvider* resource_provider) {
191  LayerImpl::DidDraw(resource_provider);
192  if (uses_mailbox_ || !external_texture_resource_)
193    return;
194  // TODO(danakj): the following assert will not be true when sending resources
195  // to a parent compositor. A synchronization scheme (double-buffering or
196  // pipelining of updates) for the client will need to exist to solve this.
197  DCHECK(!resource_provider->InUseByConsumer(external_texture_resource_));
198  resource_provider->DeleteResource(external_texture_resource_);
199  external_texture_resource_ = 0;
200}
201
202Region TextureLayerImpl::VisibleContentOpaqueRegion() const {
203  if (contents_opaque())
204    return visible_content_rect();
205
206  if (blend_background_color_ && (SkColorGetA(background_color()) == 0xFF))
207    return visible_content_rect();
208
209  return Region();
210}
211
212void TextureLayerImpl::DidLoseOutputSurface() {
213  if (external_texture_resource_ && !uses_mailbox_) {
214    ResourceProvider* resource_provider =
215        layer_tree_impl()->resource_provider();
216    resource_provider->DeleteResource(external_texture_resource_);
217  }
218  texture_copy_.reset();
219  texture_id_ = 0;
220  external_texture_resource_ = 0;
221  valid_texture_copy_ = false;
222}
223
224const char* TextureLayerImpl::LayerTypeAsString() const {
225  return "cc::TextureLayerImpl";
226}
227
228void TextureLayerImpl::FreeTextureMailbox() {
229  if (!uses_mailbox_)
230    return;
231  if (own_mailbox_) {
232    DCHECK(!external_texture_resource_);
233    if (release_callback_)
234      release_callback_->Run(texture_mailbox_.sync_point(), false);
235    texture_mailbox_ = TextureMailbox();
236    release_callback_.reset();
237  } else if (external_texture_resource_) {
238    DCHECK(!own_mailbox_);
239    ResourceProvider* resource_provider =
240        layer_tree_impl()->resource_provider();
241    resource_provider->DeleteResource(external_texture_resource_);
242    external_texture_resource_ = 0;
243  }
244}
245
246}  // namespace cc
247