| Index: gpu/command_buffer/service/texture_manager.cc
 | 
| diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
 | 
| index 27e48920ce501c572c4435da597e7d3918821743..4a2314510760eec30d78a58df857c683d4564595 100644
 | 
| --- a/gpu/command_buffer/service/texture_manager.cc
 | 
| +++ b/gpu/command_buffer/service/texture_manager.cc
 | 
| @@ -8,6 +8,7 @@
 | 
|  #include "gpu/command_buffer/common/gles2_cmd_utils.h"
 | 
|  #include "gpu/command_buffer/service/error_state.h"
 | 
|  #include "gpu/command_buffer/service/feature_info.h"
 | 
| +#include "gpu/command_buffer/service/framebuffer_manager.h"
 | 
|  #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 | 
|  #include "gpu/command_buffer/service/mailbox_manager.h"
 | 
|  #include "gpu/command_buffer/service/memory_tracking.h"
 | 
| @@ -87,10 +88,9 @@ void TextureManager::Destroy(bool have_context) {
 | 
|    DCHECK_EQ(0u, memory_tracker_unmanaged_->GetMemRepresented());
 | 
|  }
 | 
|  
 | 
| -Texture::Texture(TextureManager* manager, GLuint service_id)
 | 
| -    : manager_(manager),
 | 
| +Texture::Texture(GLuint service_id)
 | 
| +    : memory_tracking_ref_(NULL),
 | 
|        service_id_(service_id),
 | 
| -      deleted_(false),
 | 
|        cleared_(true),
 | 
|        num_uncleared_mips_(0),
 | 
|        target_(0),
 | 
| @@ -109,24 +109,48 @@ Texture::Texture(TextureManager* manager, GLuint service_id)
 | 
|        owned_(true),
 | 
|        stream_texture_(false),
 | 
|        immutable_(false),
 | 
| -      estimated_size_(0) {
 | 
| -  if (manager_) {
 | 
| -    manager_->StartTracking(this);
 | 
| -  }
 | 
| +      estimated_size_(0),
 | 
| +      can_render_condition_(CAN_RENDER_NEVER) {
 | 
|  }
 | 
|  
 | 
|  Texture::~Texture() {
 | 
| -  if (manager_) {
 | 
| -    if (owned_ && manager_->have_context_) {
 | 
| +}
 | 
| +
 | 
| +void Texture::AddTextureRef(TextureRef* ref) {
 | 
| +  DCHECK(refs_.find(ref) == refs_.end());
 | 
| +  refs_.insert(ref);
 | 
| +  if (!memory_tracking_ref_) {
 | 
| +    memory_tracking_ref_ = ref;
 | 
| +    GetMemTracker()->TrackMemAlloc(estimated_size());
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +void Texture::RemoveTextureRef(TextureRef* ref, bool have_context) {
 | 
| +  if (memory_tracking_ref_ == ref) {
 | 
| +    GetMemTracker()->TrackMemFree(estimated_size());
 | 
| +    memory_tracking_ref_ = NULL;
 | 
| +  }
 | 
| +  size_t result = refs_.erase(ref);
 | 
| +  DCHECK_EQ(result, 1u);
 | 
| +  if (refs_.empty()) {
 | 
| +    if (owned_ && have_context) {
 | 
|        GLuint id = service_id();
 | 
|        glDeleteTextures(1, &id);
 | 
|      }
 | 
| -    MarkAsDeleted();
 | 
| -    manager_->StopTracking(this);
 | 
| -    manager_ = NULL;
 | 
| +    delete this;
 | 
| +  } else if (memory_tracking_ref_ == NULL) {
 | 
| +    // TODO(piman): tune ownership semantics for cross-context group shared
 | 
| +    // textures.
 | 
| +    memory_tracking_ref_ = *refs_.begin();
 | 
| +    GetMemTracker()->TrackMemAlloc(estimated_size());
 | 
|    }
 | 
|  }
 | 
|  
 | 
| +MemoryTypeTracker* Texture::GetMemTracker() {
 | 
| +  DCHECK(memory_tracking_ref_);
 | 
| +  return memory_tracking_ref_->manager()->GetMemTracker(pool_);
 | 
| +}
 | 
| +
 | 
|  Texture::LevelInfo::LevelInfo()
 | 
|      : cleared(true),
 | 
|        target(0),
 | 
| @@ -159,44 +183,59 @@ Texture::LevelInfo::LevelInfo(const LevelInfo& rhs)
 | 
|  Texture::LevelInfo::~LevelInfo() {
 | 
|  }
 | 
|  
 | 
| -bool Texture::CanRender(const FeatureInfo* feature_info) const {
 | 
| -  if (target_ == 0) {
 | 
| -    return false;
 | 
| -  }
 | 
| +Texture::CanRenderCondition Texture::GetCanRenderCondition() const {
 | 
| +  if (target_ == 0)
 | 
| +    return CAN_RENDER_NEVER;
 | 
|  
 | 
|    if (target_ == GL_TEXTURE_EXTERNAL_OES) {
 | 
|      if (!IsStreamTexture()) {
 | 
| -      return false;
 | 
| +      return CAN_RENDER_NEVER;
 | 
|      }
 | 
|    } else {
 | 
|      if (level_infos_.empty()) {
 | 
| -      return false;
 | 
| +      return CAN_RENDER_NEVER;
 | 
|      }
 | 
|  
 | 
|      const Texture::LevelInfo& first_face = level_infos_[0][0];
 | 
|      if (first_face.width == 0 ||
 | 
|          first_face.height == 0 ||
 | 
|          first_face.depth == 0) {
 | 
| -      return false;
 | 
| +      return CAN_RENDER_NEVER;
 | 
|      }
 | 
|    }
 | 
|  
 | 
|    bool needs_mips = NeedsMips();
 | 
| -  if ((npot() && !feature_info->feature_flags().npot_ok) ||
 | 
| -      (target_ == GL_TEXTURE_RECTANGLE_ARB)) {
 | 
| -    return !needs_mips &&
 | 
| -           wrap_s_ == GL_CLAMP_TO_EDGE &&
 | 
| -           wrap_t_ == GL_CLAMP_TO_EDGE;
 | 
| -  }
 | 
|    if (needs_mips) {
 | 
| -    if (target_ == GL_TEXTURE_2D) {
 | 
| -      return texture_complete();
 | 
| -    } else {
 | 
| -      return texture_complete() && cube_complete();
 | 
| -    }
 | 
| -  } else {
 | 
| -    return true;
 | 
| +    if (!texture_complete())
 | 
| +      return CAN_RENDER_NEVER;
 | 
| +    if (target_ == GL_TEXTURE_CUBE_MAP && !cube_complete())
 | 
| +      return CAN_RENDER_NEVER;
 | 
| +  }
 | 
| +
 | 
| +  bool is_npot_compatible = !needs_mips &&
 | 
| +      wrap_s_ == GL_CLAMP_TO_EDGE &&
 | 
| +      wrap_t_ == GL_CLAMP_TO_EDGE;
 | 
| +
 | 
| +  if (!is_npot_compatible) {
 | 
| +    if (target_ == GL_TEXTURE_RECTANGLE_ARB)
 | 
| +      return CAN_RENDER_NEVER;
 | 
| +    else if (npot())
 | 
| +      return CAN_RENDER_ONLY_IF_NPOT;
 | 
|    }
 | 
| +
 | 
| +  return CAN_RENDER_ALWAYS;
 | 
| +}
 | 
| +
 | 
| +bool Texture::CanRender(const FeatureInfo* feature_info) const {
 | 
| +  switch (can_render_condition_) {
 | 
| +    case CAN_RENDER_ALWAYS:
 | 
| +      return true;
 | 
| +    case CAN_RENDER_NEVER:
 | 
| +      return false;
 | 
| +    case CAN_RENDER_ONLY_IF_NPOT:
 | 
| +      break;
 | 
| +  }
 | 
| +  return feature_info->feature_flags().npot_ok;
 | 
|  }
 | 
|  
 | 
|  void Texture::AddToSignature(
 | 
| @@ -280,6 +319,7 @@ void Texture::SetTarget(
 | 
|      immutable_ = true;
 | 
|    }
 | 
|    Update(feature_info);
 | 
| +  UpdateCanRenderCondition();
 | 
|  }
 | 
|  
 | 
|  bool Texture::CanGenerateMipmaps(
 | 
| @@ -325,13 +365,7 @@ void Texture::SetLevelCleared(GLenum target, GLint level, bool cleared) {
 | 
|              level_infos_[GLTargetToFaceIndex(target)].size());
 | 
|    Texture::LevelInfo& info =
 | 
|        level_infos_[GLTargetToFaceIndex(target)][level];
 | 
| -  if (!info.cleared) {
 | 
| -    DCHECK_NE(0, num_uncleared_mips_);
 | 
| -    --num_uncleared_mips_;
 | 
| -  } else {
 | 
| -    ++num_uncleared_mips_;
 | 
| -  }
 | 
| -  info.cleared = cleared;
 | 
| +  UpdateMipCleared(&info, cleared);
 | 
|    UpdateCleared();
 | 
|  }
 | 
|  
 | 
| @@ -343,17 +377,61 @@ void Texture::UpdateCleared() {
 | 
|    const Texture::LevelInfo& first_face = level_infos_[0][0];
 | 
|    int levels_needed = TextureManager::ComputeMipMapCount(
 | 
|        first_face.width, first_face.height, first_face.depth);
 | 
| -  cleared_ = true;
 | 
| +  bool cleared = true;
 | 
|    for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
 | 
|      for (GLint jj = 0; jj < levels_needed; ++jj) {
 | 
|        const Texture::LevelInfo& info = level_infos_[ii][jj];
 | 
|        if (info.width > 0 && info.height > 0 && info.depth > 0 &&
 | 
|            !info.cleared) {
 | 
| -        cleared_ = false;
 | 
| -        return;
 | 
| +        cleared = false;
 | 
| +        break;
 | 
|        }
 | 
|      }
 | 
|    }
 | 
| +  UpdateSafeToRenderFrom(cleared);
 | 
| +}
 | 
| +
 | 
| +void Texture::UpdateSafeToRenderFrom(bool cleared) {
 | 
| +  if (cleared_ == cleared)
 | 
| +    return;
 | 
| +  cleared_ = cleared;
 | 
| +  int delta = cleared ? -1 : +1;
 | 
| +  for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
 | 
| +    (*it)->manager()->UpdateSafeToRenderFrom(delta);
 | 
| +}
 | 
| +
 | 
| +void Texture::UpdateMipCleared(LevelInfo* info, bool cleared) {
 | 
| +  if (info->cleared == cleared)
 | 
| +    return;
 | 
| +  info->cleared = cleared;
 | 
| +  int delta = cleared ? -1 : +1;
 | 
| +  num_uncleared_mips_ += delta;
 | 
| +  for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
 | 
| +    (*it)->manager()->UpdateUnclearedMips(delta);
 | 
| +}
 | 
| +
 | 
| +void Texture::UpdateCanRenderCondition() {
 | 
| +  CanRenderCondition can_render_condition = GetCanRenderCondition();
 | 
| +  if (can_render_condition_ == can_render_condition)
 | 
| +    return;
 | 
| +  for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
 | 
| +    (*it)->manager()->UpdateCanRenderCondition(can_render_condition_,
 | 
| +                                               can_render_condition);
 | 
| +  can_render_condition_ = can_render_condition;
 | 
| +}
 | 
| +
 | 
| +void Texture::IncAllFramebufferStateChangeCount() {
 | 
| +  for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
 | 
| +    (*it)->manager()->IncFramebufferStateChangeCount();
 | 
| +}
 | 
| +
 | 
| +AsyncPixelTransferState* Texture::GetAsyncTransferState() const {
 | 
| +  for (RefSet::const_iterator it = refs_.begin(); it != refs_.end(); ++it) {
 | 
| +    AsyncPixelTransferState* state = (*it)->async_transfer_state();
 | 
| +    if (state)
 | 
| +      return state;
 | 
| +  }
 | 
| +  return NULL;
 | 
|  }
 | 
|  
 | 
|  void Texture::SetLevelInfo(
 | 
| @@ -394,17 +472,16 @@ void Texture::SetLevelInfo(
 | 
|        width, height, format, type, 4, &info.estimated_size, NULL, NULL);
 | 
|    estimated_size_ += info.estimated_size;
 | 
|  
 | 
| -  if (!info.cleared) {
 | 
| -    DCHECK_NE(0, num_uncleared_mips_);
 | 
| -    --num_uncleared_mips_;
 | 
| -  }
 | 
| -  info.cleared = cleared;
 | 
| -  if (!info.cleared) {
 | 
| -    ++num_uncleared_mips_;
 | 
| -  }
 | 
| +  UpdateMipCleared(&info, cleared);
 | 
|    max_level_set_ = std::max(max_level_set_, level);
 | 
|    Update(feature_info);
 | 
|    UpdateCleared();
 | 
| +  UpdateCanRenderCondition();
 | 
| +  if (IsAttachedToFramebuffer()) {
 | 
| +    // TODO(gman): If textures tracked which framebuffers they were attached to
 | 
| +    // we could just mark those framebuffers as not complete.
 | 
| +    IncAllFramebufferStateChangeCount();
 | 
| +  }
 | 
|  }
 | 
|  
 | 
|  bool Texture::ValidForTexture(
 | 
| @@ -499,9 +576,9 @@ GLenum Texture::SetParameter(
 | 
|        if (!feature_info->validators()->texture_pool.IsValid(param)) {
 | 
|          return GL_INVALID_ENUM;
 | 
|        }
 | 
| -      manager_->GetMemTracker(pool_)->TrackMemFree(estimated_size());
 | 
| +      GetMemTracker()->TrackMemFree(estimated_size());
 | 
|        pool_ = param;
 | 
| -      manager_->GetMemTracker(pool_)->TrackMemAlloc(estimated_size());
 | 
| +      GetMemTracker()->TrackMemAlloc(estimated_size());
 | 
|        break;
 | 
|      case GL_TEXTURE_WRAP_S:
 | 
|        if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
 | 
| @@ -532,6 +609,7 @@ GLenum Texture::SetParameter(
 | 
|    }
 | 
|    Update(feature_info);
 | 
|    UpdateCleared();
 | 
| +  UpdateCanRenderCondition();
 | 
|    return GL_NO_ERROR;
 | 
|  }
 | 
|  
 | 
| @@ -619,7 +697,7 @@ void Texture::Update(const FeatureInfo* feature_info) {
 | 
|  
 | 
|  bool Texture::ClearRenderableLevels(GLES2Decoder* decoder) {
 | 
|    DCHECK(decoder);
 | 
| -  if (SafeToRenderFrom()) {
 | 
| +  if (cleared_) {
 | 
|      return true;
 | 
|    }
 | 
|  
 | 
| @@ -637,7 +715,7 @@ bool Texture::ClearRenderableLevels(GLES2Decoder* decoder) {
 | 
|        }
 | 
|      }
 | 
|    }
 | 
| -  cleared_ = true;
 | 
| +  UpdateSafeToRenderFrom(true);
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
| @@ -674,18 +752,13 @@ bool Texture::ClearLevel(
 | 
|      return true;
 | 
|    }
 | 
|  
 | 
| -  DCHECK_NE(0, num_uncleared_mips_);
 | 
| -  --num_uncleared_mips_;
 | 
| -
 | 
|    // NOTE: It seems kind of gross to call back into the decoder for this
 | 
|    // but only the decoder knows all the state (like unpack_alignment_) that's
 | 
|    // needed to be able to call GL correctly.
 | 
| -  info.cleared = decoder->ClearLevel(
 | 
| +  bool cleared = decoder->ClearLevel(
 | 
|        service_id_, target_, info.target, info.level, info.format, info.type,
 | 
|        info.width, info.height, immutable_);
 | 
| -  if (!info.cleared) {
 | 
| -    ++num_uncleared_mips_;
 | 
| -  }
 | 
| +  UpdateMipCleared(&info, cleared);
 | 
|    return info.cleared;
 | 
|  }
 | 
|  
 | 
| @@ -704,6 +777,7 @@ void Texture::SetLevelImage(
 | 
|    DCHECK_EQ(info.target, target);
 | 
|    DCHECK_EQ(info.level, level);
 | 
|    info.image = image;
 | 
| +  UpdateCanRenderCondition();
 | 
|  }
 | 
|  
 | 
|  gfx::GLImage* Texture::GetLevelImage(
 | 
| @@ -719,6 +793,28 @@ gfx::GLImage* Texture::GetLevelImage(
 | 
|    return 0;
 | 
|  }
 | 
|  
 | 
| +
 | 
| +TextureRef::TextureRef(TextureManager* manager, Texture* texture)
 | 
| +    : manager_(manager),
 | 
| +      texture_(texture) {
 | 
| +  DCHECK(manager_);
 | 
| +  DCHECK(texture_);
 | 
| +  texture_->AddTextureRef(this);
 | 
| +  manager_->StartTracking(this);
 | 
| +}
 | 
| +
 | 
| +scoped_refptr<TextureRef> TextureRef::Create(TextureManager* manager,
 | 
| +                                             GLuint service_id) {
 | 
| +  return new TextureRef(manager, new Texture(service_id));
 | 
| +}
 | 
| +
 | 
| +TextureRef::~TextureRef() {
 | 
| +  manager_->StopTracking(this);
 | 
| +  texture_->RemoveTextureRef(this, manager_->have_context_);
 | 
| +  manager_ = NULL;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  TextureManager::TextureManager(
 | 
|      MemoryTracker* memory_tracker,
 | 
|      FeatureInfo* feature_info,
 | 
| @@ -729,6 +825,7 @@ TextureManager::TextureManager(
 | 
|        memory_tracker_unmanaged_(
 | 
|            new MemoryTypeTracker(memory_tracker, MemoryTracker::kUnmanaged)),
 | 
|        feature_info_(feature_info),
 | 
| +      framebuffer_manager_(NULL),
 | 
|        max_texture_size_(max_texture_size),
 | 
|        max_cube_map_texture_size_(max_cube_map_texture_size),
 | 
|        max_levels_(ComputeMipMapCount(max_texture_size,
 | 
| @@ -770,7 +867,7 @@ bool TextureManager::Initialize() {
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
| -scoped_refptr<Texture>
 | 
| +scoped_refptr<TextureRef>
 | 
|      TextureManager::CreateDefaultAndBlackTextures(
 | 
|          GLenum target,
 | 
|          GLuint* black_texture) {
 | 
| @@ -800,10 +897,7 @@ scoped_refptr<Texture>
 | 
|    }
 | 
|    glBindTexture(target, 0);
 | 
|  
 | 
| -  // Since we are manually setting up these textures
 | 
| -  // we need to manually manipulate some of the their bookkeeping.
 | 
| -  ++num_unrenderable_textures_;
 | 
| -  scoped_refptr<Texture> default_texture(new Texture(this, ids[1]));
 | 
| +  scoped_refptr<TextureRef> default_texture(TextureRef::Create(this, ids[1]));
 | 
|    SetTarget(default_texture, target);
 | 
|    if (needs_faces) {
 | 
|      for (int ii = 0; ii < GLES2Util::kNumFaces; ++ii) {
 | 
| @@ -846,90 +940,45 @@ bool TextureManager::ValidForTarget(
 | 
|           (target != GL_TEXTURE_2D || (depth == 1));
 | 
|  }
 | 
|  
 | 
| -void TextureManager::SetTarget(Texture* texture, GLenum target) {
 | 
| -  DCHECK(texture);
 | 
| -  if (!texture->CanRender(feature_info_)) {
 | 
| -    DCHECK_NE(0, num_unrenderable_textures_);
 | 
| -    --num_unrenderable_textures_;
 | 
| -  }
 | 
| -  texture->SetTarget(feature_info_, target, MaxLevelsForTarget(target));
 | 
| -  if (!texture->CanRender(feature_info_)) {
 | 
| -    ++num_unrenderable_textures_;
 | 
| -  }
 | 
| +void TextureManager::SetTarget(TextureRef* ref, GLenum target) {
 | 
| +  DCHECK(ref);
 | 
| +  ref->texture()->SetTarget(feature_info_, target, MaxLevelsForTarget(target));
 | 
|  }
 | 
|  
 | 
| -void TextureManager::SetStreamTexture(Texture* texture, bool stream_texture) {
 | 
| -  DCHECK(texture);
 | 
| -  if (!texture->CanRender(feature_info_)) {
 | 
| -    DCHECK_NE(0, num_unrenderable_textures_);
 | 
| -    --num_unrenderable_textures_;
 | 
| -  }
 | 
| -  texture->SetStreamTexture(stream_texture);
 | 
| -  if (!texture->CanRender(feature_info_)) {
 | 
| -    ++num_unrenderable_textures_;
 | 
| -  }
 | 
| +void TextureManager::SetStreamTexture(TextureRef* ref, bool stream_texture) {
 | 
| +  DCHECK(ref);
 | 
| +  ref->texture()->SetStreamTexture(stream_texture);
 | 
|  }
 | 
|  
 | 
| -void TextureManager::SetLevelCleared(Texture* texture,
 | 
| +void TextureManager::SetLevelCleared(TextureRef* ref,
 | 
|                                       GLenum target,
 | 
|                                       GLint level,
 | 
|                                       bool cleared) {
 | 
| -  DCHECK(texture);
 | 
| -  if (!texture->SafeToRenderFrom()) {
 | 
| -    DCHECK_NE(0, num_unsafe_textures_);
 | 
| -    --num_unsafe_textures_;
 | 
| -  }
 | 
| -  num_uncleared_mips_ -= texture->num_uncleared_mips();
 | 
| -  DCHECK_GE(num_uncleared_mips_, 0);
 | 
| -  texture->SetLevelCleared(target, level, cleared);
 | 
| -  num_uncleared_mips_ += texture->num_uncleared_mips();
 | 
| -  if (!texture->SafeToRenderFrom()) {
 | 
| -    ++num_unsafe_textures_;
 | 
| -  }
 | 
| +  DCHECK(ref);
 | 
| +  ref->texture()->SetLevelCleared(target, level, cleared);
 | 
|  }
 | 
|  
 | 
|  bool TextureManager::ClearRenderableLevels(
 | 
| -    GLES2Decoder* decoder,Texture* texture) {
 | 
| -  DCHECK(texture);
 | 
| -  if (texture->SafeToRenderFrom()) {
 | 
| -    return true;
 | 
| -  }
 | 
| -  DCHECK_NE(0, num_unsafe_textures_);
 | 
| -  --num_unsafe_textures_;
 | 
| -  num_uncleared_mips_ -= texture->num_uncleared_mips();
 | 
| -  DCHECK_GE(num_uncleared_mips_, 0);
 | 
| -  bool result = texture->ClearRenderableLevels(decoder);
 | 
| -  num_uncleared_mips_ += texture->num_uncleared_mips();
 | 
| -  if (!texture->SafeToRenderFrom()) {
 | 
| -    ++num_unsafe_textures_;
 | 
| -  }
 | 
| -  return result;
 | 
| +    GLES2Decoder* decoder, TextureRef* ref) {
 | 
| +  DCHECK(ref);
 | 
| +  return ref->texture()->ClearRenderableLevels(decoder);
 | 
|  }
 | 
|  
 | 
|  bool TextureManager::ClearTextureLevel(
 | 
| -    GLES2Decoder* decoder,Texture* texture,
 | 
| +    GLES2Decoder* decoder, TextureRef* ref,
 | 
|      GLenum target, GLint level) {
 | 
| -  DCHECK(texture);
 | 
| +  DCHECK(ref);
 | 
| +  Texture* texture = ref->texture();
 | 
|    if (texture->num_uncleared_mips() == 0) {
 | 
|      return true;
 | 
|    }
 | 
| -  num_uncleared_mips_ -= texture->num_uncleared_mips();
 | 
| -  DCHECK_GE(num_uncleared_mips_, 0);
 | 
| -  if (!texture->SafeToRenderFrom()) {
 | 
| -    DCHECK_NE(0, num_unsafe_textures_);
 | 
| -    --num_unsafe_textures_;
 | 
| -  }
 | 
|    bool result = texture->ClearLevel(decoder, target, level);
 | 
|    texture->UpdateCleared();
 | 
| -  num_uncleared_mips_ += texture->num_uncleared_mips();
 | 
| -  if (!texture->SafeToRenderFrom()) {
 | 
| -    ++num_unsafe_textures_;
 | 
| -  }
 | 
|    return result;
 | 
|  }
 | 
|  
 | 
|  void TextureManager::SetLevelInfo(
 | 
| -    Texture* texture,
 | 
| +    TextureRef* ref,
 | 
|      GLenum target,
 | 
|      GLint level,
 | 
|      GLenum internal_format,
 | 
| @@ -940,34 +989,19 @@ void TextureManager::SetLevelInfo(
 | 
|      GLenum format,
 | 
|      GLenum type,
 | 
|      bool cleared) {
 | 
| -  DCHECK(texture);
 | 
| -  if (!texture->CanRender(feature_info_)) {
 | 
| -    DCHECK_NE(0, num_unrenderable_textures_);
 | 
| -    --num_unrenderable_textures_;
 | 
| -  }
 | 
| -  if (!texture->SafeToRenderFrom()) {
 | 
| -    DCHECK_NE(0, num_unsafe_textures_);
 | 
| -    --num_unsafe_textures_;
 | 
| -  }
 | 
| -  num_uncleared_mips_ -= texture->num_uncleared_mips();
 | 
| -  DCHECK_GE(num_uncleared_mips_, 0);
 | 
| +  DCHECK(ref);
 | 
| +  Texture* texture = ref->texture();
 | 
|  
 | 
| -  GetMemTracker(texture->pool_)->TrackMemFree(texture->estimated_size());
 | 
| +  texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
 | 
|    texture->SetLevelInfo(
 | 
|        feature_info_, target, level, internal_format, width, height, depth,
 | 
|        border, format, type, cleared);
 | 
| -  GetMemTracker(texture->pool_)->TrackMemAlloc(texture->estimated_size());
 | 
| -
 | 
| -  num_uncleared_mips_ += texture->num_uncleared_mips();
 | 
| -  if (!texture->CanRender(feature_info_)) {
 | 
| -    ++num_unrenderable_textures_;
 | 
| -  }
 | 
| -  if (!texture->SafeToRenderFrom()) {
 | 
| -    ++num_unsafe_textures_;
 | 
| -  }
 | 
| +  texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
 | 
|  }
 | 
|  
 | 
| -TextureDefinition* TextureManager::Save(Texture* texture) {
 | 
| +TextureDefinition* TextureManager::Save(TextureRef* ref) {
 | 
| +  DCHECK(ref);
 | 
| +  Texture* texture = ref->texture();
 | 
|    DCHECK(texture->owned_);
 | 
|  
 | 
|    if (texture->IsAttachedToFramebuffer())
 | 
| @@ -993,7 +1027,7 @@ TextureDefinition* TextureManager::Save(Texture* texture) {
 | 
|                                         level_info.type,
 | 
|                                         level_info.cleared));
 | 
|  
 | 
| -      SetLevelInfo(texture,
 | 
| +      SetLevelInfo(ref,
 | 
|                     target,
 | 
|                     level,
 | 
|                     GL_RGBA,
 | 
| @@ -1032,8 +1066,10 @@ TextureDefinition* TextureManager::Save(Texture* texture) {
 | 
|  bool TextureManager::Restore(
 | 
|      const char* function_name,
 | 
|      GLES2Decoder* decoder,
 | 
| -    Texture* texture,
 | 
| +    TextureRef* ref,
 | 
|      TextureDefinition* definition) {
 | 
| +  DCHECK(ref);
 | 
| +  Texture* texture = ref->texture();
 | 
|    DCHECK(texture->owned_);
 | 
|  
 | 
|    scoped_ptr<TextureDefinition> scoped_definition(definition);
 | 
| @@ -1061,7 +1097,7 @@ bool TextureManager::Restore(
 | 
|        const TextureDefinition::LevelInfo& level_info =
 | 
|            level <= new_max_level ? definition->level_infos()[face][level]
 | 
|                                   : TextureDefinition::LevelInfo();
 | 
| -      SetLevelInfo(texture,
 | 
| +      SetLevelInfo(ref,
 | 
|                     target,
 | 
|                     level,
 | 
|                     level_info.internal_format,
 | 
| @@ -1081,19 +1117,18 @@ bool TextureManager::Restore(
 | 
|    glBindTexture(texture->target(), texture->service_id());
 | 
|    texture->SetImmutable(definition->immutable());
 | 
|    texture->SetStreamTexture(definition->stream_texture());
 | 
| -
 | 
|    ErrorState* error_state = decoder->GetErrorState();
 | 
| -  SetParameter(function_name, error_state, texture, GL_TEXTURE_MIN_FILTER,
 | 
| +  SetParameter(function_name, error_state, ref, GL_TEXTURE_MIN_FILTER,
 | 
|                 definition->min_filter());
 | 
| -  SetParameter(function_name, error_state, texture, GL_TEXTURE_MAG_FILTER,
 | 
| +  SetParameter(function_name, error_state, ref, GL_TEXTURE_MAG_FILTER,
 | 
|                 definition->mag_filter());
 | 
| -  SetParameter(function_name, error_state, texture, GL_TEXTURE_WRAP_S,
 | 
| +  SetParameter(function_name, error_state, ref, GL_TEXTURE_WRAP_S,
 | 
|                 definition->wrap_s());
 | 
| -  SetParameter(function_name, error_state, texture, GL_TEXTURE_WRAP_T,
 | 
| +  SetParameter(function_name, error_state, ref, GL_TEXTURE_WRAP_T,
 | 
|                 definition->wrap_t());
 | 
|    if (feature_info_->validators()->texture_parameter.IsValid(
 | 
|        GL_TEXTURE_USAGE_ANGLE)) {
 | 
| -    SetParameter(function_name, error_state, texture, GL_TEXTURE_USAGE_ANGLE,
 | 
| +    SetParameter(function_name, error_state, ref, GL_TEXTURE_USAGE_ANGLE,
 | 
|                   definition->usage());
 | 
|    }
 | 
|  
 | 
| @@ -1102,17 +1137,10 @@ bool TextureManager::Restore(
 | 
|  
 | 
|  void TextureManager::SetParameter(
 | 
|      const char* function_name, ErrorState* error_state,
 | 
| -    Texture* texture, GLenum pname, GLint param) {
 | 
| +    TextureRef* ref, GLenum pname, GLint param) {
 | 
|    DCHECK(error_state);
 | 
| -  DCHECK(texture);
 | 
| -  if (!texture->CanRender(feature_info_)) {
 | 
| -    DCHECK_NE(0, num_unrenderable_textures_);
 | 
| -    --num_unrenderable_textures_;
 | 
| -  }
 | 
| -  if (!texture->SafeToRenderFrom()) {
 | 
| -    DCHECK_NE(0, num_unsafe_textures_);
 | 
| -    --num_unsafe_textures_;
 | 
| -  }
 | 
| +  DCHECK(ref);
 | 
| +  Texture* texture = ref->texture();
 | 
|    GLenum result = texture->SetParameter(feature_info_, pname, param);
 | 
|    if (result != GL_NO_ERROR) {
 | 
|      if (result == GL_INVALID_ENUM) {
 | 
| @@ -1129,59 +1157,28 @@ void TextureManager::SetParameter(
 | 
|        glTexParameteri(texture->target(), pname, param);
 | 
|      }
 | 
|    }
 | 
| -
 | 
| -  if (!texture->CanRender(feature_info_)) {
 | 
| -    ++num_unrenderable_textures_;
 | 
| -  }
 | 
| -  if (!texture->SafeToRenderFrom()) {
 | 
| -    ++num_unsafe_textures_;
 | 
| -  }
 | 
|  }
 | 
|  
 | 
| -bool TextureManager::MarkMipmapsGenerated(Texture* texture) {
 | 
| -  DCHECK(texture);
 | 
| -  if (!texture->CanRender(feature_info_)) {
 | 
| -    DCHECK_NE(0, num_unrenderable_textures_);
 | 
| -    --num_unrenderable_textures_;
 | 
| -  }
 | 
| -  if (!texture->SafeToRenderFrom()) {
 | 
| -    DCHECK_NE(0, num_unsafe_textures_);
 | 
| -    --num_unsafe_textures_;
 | 
| -  }
 | 
| -  num_uncleared_mips_ -= texture->num_uncleared_mips();
 | 
| -  DCHECK_GE(num_uncleared_mips_, 0);
 | 
| -  GetMemTracker(texture->pool_)->TrackMemFree(texture->estimated_size());
 | 
| +bool TextureManager::MarkMipmapsGenerated(TextureRef* ref) {
 | 
| +  DCHECK(ref);
 | 
| +  Texture* texture = ref->texture();
 | 
| +  texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
 | 
|    bool result = texture->MarkMipmapsGenerated(feature_info_);
 | 
| -  GetMemTracker(texture->pool_)->TrackMemAlloc(texture->estimated_size());
 | 
| -
 | 
| -  num_uncleared_mips_ += texture->num_uncleared_mips();
 | 
| -  if (!texture->CanRender(feature_info_)) {
 | 
| -    ++num_unrenderable_textures_;
 | 
| -  }
 | 
| -  if (!texture->SafeToRenderFrom()) {
 | 
| -    ++num_unsafe_textures_;
 | 
| -  }
 | 
| +  texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
 | 
|    return result;
 | 
|  }
 | 
|  
 | 
| -Texture* TextureManager::CreateTexture(
 | 
| +TextureRef* TextureManager::CreateTexture(
 | 
|      GLuint client_id, GLuint service_id) {
 | 
|    DCHECK_NE(0u, service_id);
 | 
| -  scoped_refptr<Texture> texture(new Texture(this, service_id));
 | 
| +  scoped_refptr<TextureRef> ref(TextureRef::Create(this, service_id));
 | 
|    std::pair<TextureMap::iterator, bool> result =
 | 
| -      textures_.insert(std::make_pair(client_id, texture));
 | 
| +      textures_.insert(std::make_pair(client_id, ref));
 | 
|    DCHECK(result.second);
 | 
| -  if (!texture->CanRender(feature_info_)) {
 | 
| -    ++num_unrenderable_textures_;
 | 
| -  }
 | 
| -  if (!texture->SafeToRenderFrom()) {
 | 
| -    ++num_unsafe_textures_;
 | 
| -  }
 | 
| -  num_uncleared_mips_ += texture->num_uncleared_mips();
 | 
| -  return texture.get();
 | 
| +  return ref.get();
 | 
|  }
 | 
|  
 | 
| -Texture* TextureManager::GetTexture(
 | 
| +TextureRef* TextureManager::GetTexture(
 | 
|      GLuint client_id) const {
 | 
|    TextureMap::const_iterator it = textures_.find(client_id);
 | 
|    return it != textures_.end() ? it->second : NULL;
 | 
| @@ -1190,17 +1187,22 @@ Texture* TextureManager::GetTexture(
 | 
|  void TextureManager::RemoveTexture(GLuint client_id) {
 | 
|    TextureMap::iterator it = textures_.find(client_id);
 | 
|    if (it != textures_.end()) {
 | 
| -    Texture* texture = it->second;
 | 
| -    texture->MarkAsDeleted();
 | 
|      textures_.erase(it);
 | 
|    }
 | 
|  }
 | 
|  
 | 
| -void TextureManager::StartTracking(Texture* /* texture */) {
 | 
| +void TextureManager::StartTracking(TextureRef* ref) {
 | 
| +  Texture* texture = ref->texture();
 | 
|    ++texture_count_;
 | 
| +  num_uncleared_mips_ += texture->num_uncleared_mips();
 | 
| +  if (!texture->SafeToRenderFrom())
 | 
| +    ++num_unsafe_textures_;
 | 
| +  if (!texture->CanRender(feature_info_))
 | 
| +    ++num_unrenderable_textures_;
 | 
|  }
 | 
|  
 | 
| -void TextureManager::StopTracking(Texture* texture) {
 | 
| +void TextureManager::StopTracking(TextureRef* ref) {
 | 
| +  Texture* texture = ref->texture();
 | 
|    --texture_count_;
 | 
|    if (!texture->CanRender(feature_info_)) {
 | 
|      DCHECK_NE(0, num_unrenderable_textures_);
 | 
| @@ -1212,7 +1214,6 @@ void TextureManager::StopTracking(Texture* texture) {
 | 
|    }
 | 
|    num_uncleared_mips_ -= texture->num_uncleared_mips();
 | 
|    DCHECK_GE(num_uncleared_mips_, 0);
 | 
| -  GetMemTracker(texture->pool_)->TrackMemFree(texture->estimated_size());
 | 
|  }
 | 
|  
 | 
|  MemoryTypeTracker* TextureManager::GetMemTracker(GLenum tracking_pool) {
 | 
| @@ -1234,7 +1235,7 @@ bool TextureManager::GetClientId(GLuint service_id, GLuint* client_id) const {
 | 
|    // This doesn't need to be fast. It's only used during slow queries.
 | 
|    for (TextureMap::const_iterator it = textures_.begin();
 | 
|         it != textures_.end(); ++it) {
 | 
| -    if (it->second->service_id() == service_id) {
 | 
| +    if (it->second->texture()->service_id() == service_id) {
 | 
|        *client_id = it->first;
 | 
|        return true;
 | 
|      }
 | 
| @@ -1248,34 +1249,51 @@ GLsizei TextureManager::ComputeMipMapCount(
 | 
|  }
 | 
|  
 | 
|  void TextureManager::SetLevelImage(
 | 
| -    Texture* texture,
 | 
| +    TextureRef* ref,
 | 
|      GLenum target,
 | 
|      GLint level,
 | 
|      gfx::GLImage* image) {
 | 
| -  DCHECK(texture);
 | 
| -  if (!texture->CanRender(feature_info_)) {
 | 
| -    DCHECK_NE(0, num_unrenderable_textures_);
 | 
| -    --num_unrenderable_textures_;
 | 
| -  }
 | 
| -  if (!texture->SafeToRenderFrom()) {
 | 
| -    DCHECK_NE(0, num_unsafe_textures_);
 | 
| -    --num_unsafe_textures_;
 | 
| -  }
 | 
| -  texture->SetLevelImage(feature_info_, target, level, image);
 | 
| -  if (!texture->CanRender(feature_info_)) {
 | 
| -    ++num_unrenderable_textures_;
 | 
| -  }
 | 
| -  if (!texture->SafeToRenderFrom()) {
 | 
| -    ++num_unsafe_textures_;
 | 
| -  }
 | 
| +  DCHECK(ref);
 | 
| +  ref->texture()->SetLevelImage(feature_info_, target, level, image);
 | 
|  }
 | 
|  
 | 
|  void TextureManager::AddToSignature(
 | 
| -    Texture* texture,
 | 
| +    TextureRef* ref,
 | 
|      GLenum target,
 | 
|      GLint level,
 | 
|      std::string* signature) const {
 | 
| -  texture->AddToSignature(feature_info_.get(), target, level, signature);
 | 
| +  ref->texture()->AddToSignature(feature_info_.get(), target, level, signature);
 | 
| +}
 | 
| +
 | 
| +void TextureManager::UpdateSafeToRenderFrom(int delta) {
 | 
| +  num_unsafe_textures_ += delta;
 | 
| +  DCHECK_GE(num_unsafe_textures_, 0);
 | 
| +}
 | 
| +
 | 
| +void TextureManager::UpdateUnclearedMips(int delta) {
 | 
| +  num_uncleared_mips_ += delta;
 | 
| +  DCHECK_GE(num_uncleared_mips_, 0);
 | 
| +}
 | 
| +
 | 
| +void TextureManager::UpdateCanRenderCondition(
 | 
| +    Texture::CanRenderCondition old_condition,
 | 
| +    Texture::CanRenderCondition new_condition) {
 | 
| +  if (old_condition == Texture::CAN_RENDER_NEVER ||
 | 
| +      (old_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
 | 
| +       !feature_info_->feature_flags().npot_ok)) {
 | 
| +    DCHECK_GT(num_unrenderable_textures_, 0);
 | 
| +    --num_unrenderable_textures_;
 | 
| +  }
 | 
| +  if (new_condition == Texture::CAN_RENDER_NEVER ||
 | 
| +      (new_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
 | 
| +       !feature_info_->feature_flags().npot_ok))
 | 
| +    ++num_unrenderable_textures_;
 | 
| +}
 | 
| +
 | 
| +void TextureManager::IncFramebufferStateChangeCount() {
 | 
| +  if (framebuffer_manager_)
 | 
| +    framebuffer_manager_->IncFramebufferStateChangeCount();
 | 
| +
 | 
|  }
 | 
|  
 | 
|  }  // namespace gles2
 | 
| 
 |