root/cc/layers/texture_layer_impl.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. valid_texture_copy_
  2. SetTextureMailbox
  3. CreateLayerImpl
  4. PushPropertiesTo
  5. WillDraw
  6. AppendQuads
  7. DidDraw
  8. VisibleContentOpaqueRegion
  9. ReleaseResources
  10. SetTextureId
  11. SetPremultipliedAlpha
  12. SetBlendBackgroundColor
  13. SetFlipped
  14. SetUVTopLeft
  15. SetUVBottomRight
  16. SetVertexOpacity
  17. LayerTypeAsString
  18. FreeTextureMailbox

// Copyright 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cc/layers/texture_layer_impl.h"

#include <vector>

#include "base/strings/stringprintf.h"
#include "cc/layers/quad_sink.h"
#include "cc/output/renderer.h"
#include "cc/quads/texture_draw_quad.h"
#include "cc/resources/platform_color.h"
#include "cc/resources/scoped_resource.h"
#include "cc/resources/single_release_callback.h"
#include "cc/trees/layer_tree_impl.h"

namespace cc {

TextureLayerImpl::TextureLayerImpl(LayerTreeImpl* tree_impl,
                                   int id,
                                   bool uses_mailbox)
    : LayerImpl(tree_impl, id),
      texture_id_(0),
      external_texture_resource_(0),
      premultiplied_alpha_(true),
      blend_background_color_(false),
      flipped_(true),
      uv_top_left_(0.f, 0.f),
      uv_bottom_right_(1.f, 1.f),
      uses_mailbox_(uses_mailbox),
      own_mailbox_(false),
      valid_texture_copy_(false) {
  vertex_opacity_[0] = 1.0f;
  vertex_opacity_[1] = 1.0f;
  vertex_opacity_[2] = 1.0f;
  vertex_opacity_[3] = 1.0f;
}

TextureLayerImpl::~TextureLayerImpl() { FreeTextureMailbox(); }

void TextureLayerImpl::SetTextureMailbox(
    const TextureMailbox& mailbox,
    scoped_ptr<SingleReleaseCallback> release_callback) {
  DCHECK(uses_mailbox_);
  DCHECK_EQ(mailbox.IsValid(), !!release_callback);
  FreeTextureMailbox();
  texture_mailbox_ = mailbox;
  release_callback_ = release_callback.Pass();
  own_mailbox_ = true;
  valid_texture_copy_ = false;
  SetNeedsPushProperties();
}

scoped_ptr<LayerImpl> TextureLayerImpl::CreateLayerImpl(
    LayerTreeImpl* tree_impl) {
  return TextureLayerImpl::Create(tree_impl, id(), uses_mailbox_).
      PassAs<LayerImpl>();
}

void TextureLayerImpl::PushPropertiesTo(LayerImpl* layer) {
  LayerImpl::PushPropertiesTo(layer);

  TextureLayerImpl* texture_layer = static_cast<TextureLayerImpl*>(layer);
  texture_layer->SetFlipped(flipped_);
  texture_layer->SetUVTopLeft(uv_top_left_);
  texture_layer->SetUVBottomRight(uv_bottom_right_);
  texture_layer->SetVertexOpacity(vertex_opacity_);
  texture_layer->SetPremultipliedAlpha(premultiplied_alpha_);
  texture_layer->SetBlendBackgroundColor(blend_background_color_);
  if (uses_mailbox_ && own_mailbox_) {
    texture_layer->SetTextureMailbox(texture_mailbox_,
                                     release_callback_.Pass());
    own_mailbox_ = false;
  } else {
    texture_layer->SetTextureId(texture_id_);
  }
}

bool TextureLayerImpl::WillDraw(DrawMode draw_mode,
                                ResourceProvider* resource_provider) {
  if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
    return false;

  if (uses_mailbox_) {
    if (own_mailbox_) {
      DCHECK(!external_texture_resource_);
      if ((draw_mode == DRAW_MODE_HARDWARE && texture_mailbox_.IsTexture()) ||
          (draw_mode == DRAW_MODE_SOFTWARE &&
           texture_mailbox_.IsSharedMemory())) {
        external_texture_resource_ =
            resource_provider->CreateResourceFromTextureMailbox(
                texture_mailbox_,
                release_callback_.Pass());
        DCHECK(external_texture_resource_);
        texture_copy_.reset();
        valid_texture_copy_ = false;
      }
      if (external_texture_resource_)
        own_mailbox_ = false;
    }

    if (!valid_texture_copy_ && draw_mode == DRAW_MODE_HARDWARE &&
        texture_mailbox_.IsSharedMemory()) {
      DCHECK(!external_texture_resource_);
      // Have to upload a copy to a texture for it to be used in a
      // hardware draw.
      if (!texture_copy_)
        texture_copy_ = ScopedResource::Create(resource_provider);
      if (texture_copy_->size() != texture_mailbox_.shared_memory_size() ||
          resource_provider->InUseByConsumer(texture_copy_->id()))
        texture_copy_->Free();

      if (!texture_copy_->id()) {
        texture_copy_->Allocate(texture_mailbox_.shared_memory_size(),
                                ResourceProvider::TextureUsageAny,
                                resource_provider->best_texture_format());
      }

      if (texture_copy_->id()) {
        std::vector<uint8> swizzled;
        uint8* pixels =
            static_cast<uint8*>(texture_mailbox_.shared_memory()->memory());

        if (!PlatformColor::SameComponentOrder(texture_copy_->format())) {
          // Swizzle colors. This is slow, but should be really uncommon.
          swizzled.resize(texture_mailbox_.SharedMemorySizeInBytes());
          for (size_t i = 0; i < texture_mailbox_.SharedMemorySizeInBytes();
               i += 4) {
            swizzled[i] = pixels[i + 2];
            swizzled[i + 1] = pixels[i + 1];
            swizzled[i + 2] = pixels[i];
            swizzled[i + 3] = pixels[i + 3];
          }
          pixels = &swizzled[0];
        }

        resource_provider->SetPixels(
            texture_copy_->id(),
            pixels,
            gfx::Rect(texture_mailbox_.shared_memory_size()),
            gfx::Rect(texture_mailbox_.shared_memory_size()),
            gfx::Vector2d());

        valid_texture_copy_ = true;
      }
    }
  } else if (texture_id_) {
    DCHECK(!external_texture_resource_);
    if (draw_mode == DRAW_MODE_HARDWARE) {
      external_texture_resource_ =
          resource_provider->CreateResourceFromExternalTexture(
              GL_TEXTURE_2D,
              texture_id_);
    }
  }
  return (external_texture_resource_ || valid_texture_copy_) &&
         LayerImpl::WillDraw(draw_mode, resource_provider);
}

void TextureLayerImpl::AppendQuads(QuadSink* quad_sink,
                                   AppendQuadsData* append_quads_data) {
  DCHECK(external_texture_resource_ || valid_texture_copy_);

  SharedQuadState* shared_quad_state =
      quad_sink->UseSharedQuadState(CreateSharedQuadState());
  AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);

  SkColor bg_color = blend_background_color_ ?
      background_color() : SK_ColorTRANSPARENT;
  bool opaque = contents_opaque() || (SkColorGetA(bg_color) == 0xFF);

  gfx::Rect quad_rect(content_bounds());
  gfx::Rect opaque_rect = opaque ? quad_rect : gfx::Rect();
  gfx::Rect visible_quad_rect = quad_sink->UnoccludedContentRect(
      quad_rect, draw_properties().target_space_transform);
  if (visible_quad_rect.IsEmpty())
    return;

  scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
  ResourceProvider::ResourceId id =
      valid_texture_copy_ ? texture_copy_->id() : external_texture_resource_;
  quad->SetNew(shared_quad_state,
               quad_rect,
               opaque_rect,
               visible_quad_rect,
               id,
               premultiplied_alpha_,
               uv_top_left_,
               uv_bottom_right_,
               bg_color,
               vertex_opacity_,
               flipped_);
  quad_sink->Append(quad.PassAs<DrawQuad>());
}

void TextureLayerImpl::DidDraw(ResourceProvider* resource_provider) {
  LayerImpl::DidDraw(resource_provider);
  if (uses_mailbox_ || !external_texture_resource_)
    return;
  // TODO(danakj): the following assert will not be true when sending resources
  // to a parent compositor. A synchronization scheme (double-buffering or
  // pipelining of updates) for the client will need to exist to solve this.
  DCHECK(!resource_provider->InUseByConsumer(external_texture_resource_));
  resource_provider->DeleteResource(external_texture_resource_);
  external_texture_resource_ = 0;
}

Region TextureLayerImpl::VisibleContentOpaqueRegion() const {
  if (contents_opaque())
    return visible_content_rect();

  if (blend_background_color_ && (SkColorGetA(background_color()) == 0xFF))
    return visible_content_rect();

  return Region();
}

void TextureLayerImpl::ReleaseResources() {
  if (external_texture_resource_ && !uses_mailbox_) {
    ResourceProvider* resource_provider =
        layer_tree_impl()->resource_provider();
    resource_provider->DeleteResource(external_texture_resource_);
  } else {
    FreeTextureMailbox();
  }
  texture_copy_.reset();
  texture_id_ = 0;
  external_texture_resource_ = 0;
  valid_texture_copy_ = false;
}

void TextureLayerImpl::SetTextureId(unsigned id) {
  texture_id_ = id;
  SetNeedsPushProperties();
}

void TextureLayerImpl::SetPremultipliedAlpha(bool premultiplied_alpha) {
  premultiplied_alpha_ = premultiplied_alpha;
  SetNeedsPushProperties();
}

void TextureLayerImpl::SetBlendBackgroundColor(bool blend) {
  blend_background_color_ = blend;
  SetNeedsPushProperties();
}

void TextureLayerImpl::SetFlipped(bool flipped) {
  flipped_ = flipped;
  SetNeedsPushProperties();
}

void TextureLayerImpl::SetUVTopLeft(const gfx::PointF top_left) {
  uv_top_left_ = top_left;
  SetNeedsPushProperties();
}

void TextureLayerImpl::SetUVBottomRight(const gfx::PointF bottom_right) {
  uv_bottom_right_ = bottom_right;
  SetNeedsPushProperties();
}

// 1--2
// |  |
// 0--3
void TextureLayerImpl::SetVertexOpacity(const float vertex_opacity[4]) {
  vertex_opacity_[0] = vertex_opacity[0];
  vertex_opacity_[1] = vertex_opacity[1];
  vertex_opacity_[2] = vertex_opacity[2];
  vertex_opacity_[3] = vertex_opacity[3];
  SetNeedsPushProperties();
}

const char* TextureLayerImpl::LayerTypeAsString() const {
  return "cc::TextureLayerImpl";
}

void TextureLayerImpl::FreeTextureMailbox() {
  if (!uses_mailbox_)
    return;
  if (own_mailbox_) {
    DCHECK(!external_texture_resource_);
    if (release_callback_)
      release_callback_->Run(texture_mailbox_.sync_point(), false);
    texture_mailbox_ = TextureMailbox();
    release_callback_.reset();
  } else if (external_texture_resource_) {
    DCHECK(!own_mailbox_);
    ResourceProvider* resource_provider =
        layer_tree_impl()->resource_provider();
    resource_provider->DeleteResource(external_texture_resource_);
    external_texture_resource_ = 0;
  }
}

}  // namespace cc

/* [<][>][^][v][top][bottom][index][help] */