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