Home | History | Annotate | Download | only in service
      1 // Copyright (c) 2012 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 "gpu/command_buffer/service/texture_manager.h"
      6 #include "base/bits.h"
      7 #include "base/strings/stringprintf.h"
      8 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
      9 #include "gpu/command_buffer/service/error_state.h"
     10 #include "gpu/command_buffer/service/feature_info.h"
     11 #include "gpu/command_buffer/service/framebuffer_manager.h"
     12 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
     13 #include "gpu/command_buffer/service/mailbox_manager.h"
     14 #include "gpu/command_buffer/service/memory_tracking.h"
     15 #include "gpu/command_buffer/service/stream_texture_manager.h"
     16 
     17 namespace gpu {
     18 namespace gles2 {
     19 
     20 static size_t GLTargetToFaceIndex(GLenum target) {
     21   switch (target) {
     22     case GL_TEXTURE_2D:
     23     case GL_TEXTURE_EXTERNAL_OES:
     24     case GL_TEXTURE_RECTANGLE_ARB:
     25       return 0;
     26     case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
     27       return 0;
     28     case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
     29       return 1;
     30     case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
     31       return 2;
     32     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
     33       return 3;
     34     case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
     35       return 4;
     36     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
     37       return 5;
     38     default:
     39       NOTREACHED();
     40       return 0;
     41   }
     42 }
     43 
     44 static size_t FaceIndexToGLTarget(size_t index) {
     45   switch (index) {
     46     case 0:
     47       return GL_TEXTURE_CUBE_MAP_POSITIVE_X;
     48     case 1:
     49       return GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
     50     case 2:
     51       return GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
     52     case 3:
     53       return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
     54     case 4:
     55       return GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
     56     case 5:
     57       return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
     58     default:
     59       NOTREACHED();
     60       return 0;
     61   }
     62 }
     63 
     64 TextureManager::DestructionObserver::DestructionObserver() {}
     65 
     66 TextureManager::DestructionObserver::~DestructionObserver() {}
     67 
     68 TextureManager::~TextureManager() {
     69   FOR_EACH_OBSERVER(DestructionObserver,
     70                     destruction_observers_,
     71                     OnTextureManagerDestroying(this));
     72 
     73   DCHECK(textures_.empty());
     74 
     75   // If this triggers, that means something is keeping a reference to
     76   // a Texture belonging to this.
     77   CHECK_EQ(texture_count_, 0u);
     78 
     79   DCHECK_EQ(0, num_unrenderable_textures_);
     80   DCHECK_EQ(0, num_unsafe_textures_);
     81   DCHECK_EQ(0, num_uncleared_mips_);
     82 }
     83 
     84 void TextureManager::Destroy(bool have_context) {
     85   have_context_ = have_context;
     86   textures_.clear();
     87   for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
     88     default_textures_[ii] = NULL;
     89   }
     90 
     91   if (have_context) {
     92     glDeleteTextures(arraysize(black_texture_ids_), black_texture_ids_);
     93   }
     94 
     95   DCHECK_EQ(0u, memory_tracker_managed_->GetMemRepresented());
     96   DCHECK_EQ(0u, memory_tracker_unmanaged_->GetMemRepresented());
     97 }
     98 
     99 Texture::Texture(GLuint service_id)
    100     : mailbox_manager_(NULL),
    101       memory_tracking_ref_(NULL),
    102       service_id_(service_id),
    103       cleared_(true),
    104       num_uncleared_mips_(0),
    105       target_(0),
    106       min_filter_(GL_NEAREST_MIPMAP_LINEAR),
    107       mag_filter_(GL_LINEAR),
    108       wrap_s_(GL_REPEAT),
    109       wrap_t_(GL_REPEAT),
    110       usage_(GL_NONE),
    111       pool_(GL_TEXTURE_POOL_UNMANAGED_CHROMIUM),
    112       max_level_set_(-1),
    113       texture_complete_(false),
    114       cube_complete_(false),
    115       npot_(false),
    116       has_been_bound_(false),
    117       framebuffer_attachment_count_(0),
    118       stream_texture_(false),
    119       immutable_(false),
    120       estimated_size_(0),
    121       can_render_condition_(CAN_RENDER_ALWAYS) {
    122 }
    123 
    124 Texture::~Texture() {
    125   if (mailbox_manager_)
    126     mailbox_manager_->TextureDeleted(this);
    127 }
    128 
    129 void Texture::AddTextureRef(TextureRef* ref) {
    130   DCHECK(refs_.find(ref) == refs_.end());
    131   refs_.insert(ref);
    132   if (!memory_tracking_ref_) {
    133     memory_tracking_ref_ = ref;
    134     GetMemTracker()->TrackMemAlloc(estimated_size());
    135   }
    136 }
    137 
    138 void Texture::RemoveTextureRef(TextureRef* ref, bool have_context) {
    139   if (memory_tracking_ref_ == ref) {
    140     GetMemTracker()->TrackMemFree(estimated_size());
    141     memory_tracking_ref_ = NULL;
    142   }
    143   size_t result = refs_.erase(ref);
    144   DCHECK_EQ(result, 1u);
    145   if (refs_.empty()) {
    146     if (have_context) {
    147       GLuint id = service_id();
    148       glDeleteTextures(1, &id);
    149     }
    150     delete this;
    151   } else if (memory_tracking_ref_ == NULL) {
    152     // TODO(piman): tune ownership semantics for cross-context group shared
    153     // textures.
    154     memory_tracking_ref_ = *refs_.begin();
    155     GetMemTracker()->TrackMemAlloc(estimated_size());
    156   }
    157 }
    158 
    159 MemoryTypeTracker* Texture::GetMemTracker() {
    160   DCHECK(memory_tracking_ref_);
    161   return memory_tracking_ref_->manager()->GetMemTracker(pool_);
    162 }
    163 
    164 Texture::LevelInfo::LevelInfo()
    165     : cleared(true),
    166       target(0),
    167       level(-1),
    168       internal_format(0),
    169       width(0),
    170       height(0),
    171       depth(0),
    172       border(0),
    173       format(0),
    174       type(0),
    175       estimated_size(0) {
    176 }
    177 
    178 Texture::LevelInfo::LevelInfo(const LevelInfo& rhs)
    179     : cleared(rhs.cleared),
    180       target(rhs.target),
    181       level(rhs.level),
    182       internal_format(rhs.internal_format),
    183       width(rhs.width),
    184       height(rhs.height),
    185       depth(rhs.depth),
    186       border(rhs.border),
    187       format(rhs.format),
    188       type(rhs.type),
    189       image(rhs.image),
    190       estimated_size(rhs.estimated_size) {
    191 }
    192 
    193 Texture::LevelInfo::~LevelInfo() {
    194 }
    195 
    196 Texture::CanRenderCondition Texture::GetCanRenderCondition() const {
    197   if (target_ == 0)
    198     return CAN_RENDER_ALWAYS;
    199 
    200   if (target_ == GL_TEXTURE_EXTERNAL_OES) {
    201     if (!IsStreamTexture()) {
    202       return CAN_RENDER_NEVER;
    203     }
    204   } else {
    205     if (level_infos_.empty()) {
    206       return CAN_RENDER_NEVER;
    207     }
    208 
    209     const Texture::LevelInfo& first_face = level_infos_[0][0];
    210     if (first_face.width == 0 ||
    211         first_face.height == 0 ||
    212         first_face.depth == 0) {
    213       return CAN_RENDER_NEVER;
    214     }
    215   }
    216 
    217   bool needs_mips = NeedsMips();
    218   if (needs_mips) {
    219     if (!texture_complete())
    220       return CAN_RENDER_NEVER;
    221     if (target_ == GL_TEXTURE_CUBE_MAP && !cube_complete())
    222       return CAN_RENDER_NEVER;
    223   }
    224 
    225   bool is_npot_compatible = !needs_mips &&
    226       wrap_s_ == GL_CLAMP_TO_EDGE &&
    227       wrap_t_ == GL_CLAMP_TO_EDGE;
    228 
    229   if (!is_npot_compatible) {
    230     if (target_ == GL_TEXTURE_RECTANGLE_ARB)
    231       return CAN_RENDER_NEVER;
    232     else if (npot())
    233       return CAN_RENDER_ONLY_IF_NPOT;
    234   }
    235 
    236   return CAN_RENDER_ALWAYS;
    237 }
    238 
    239 bool Texture::CanRender(const FeatureInfo* feature_info) const {
    240   switch (can_render_condition_) {
    241     case CAN_RENDER_ALWAYS:
    242       return true;
    243     case CAN_RENDER_NEVER:
    244       return false;
    245     case CAN_RENDER_ONLY_IF_NPOT:
    246       break;
    247   }
    248   return feature_info->feature_flags().npot_ok;
    249 }
    250 
    251 void Texture::AddToSignature(
    252     const FeatureInfo* feature_info,
    253     GLenum target,
    254     GLint level,
    255     std::string* signature) const {
    256   DCHECK(feature_info);
    257   DCHECK(signature);
    258   DCHECK_GE(level, 0);
    259   DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
    260             level_infos_.size());
    261   DCHECK_LT(static_cast<size_t>(level),
    262             level_infos_[GLTargetToFaceIndex(target)].size());
    263   const Texture::LevelInfo& info =
    264       level_infos_[GLTargetToFaceIndex(target)][level];
    265   *signature += base::StringPrintf(
    266       "|Texture|target=%04x|level=%d|internal_format=%04x"
    267       "|width=%d|height=%d|depth=%d|border=%d|format=%04x|type=%04x"
    268       "|image=%d|canrender=%d|canrenderto=%d|npot_=%d"
    269       "|min_filter=%04x|mag_filter=%04x|wrap_s=%04x|wrap_t=%04x"
    270       "|usage=%04x",
    271       target, level, info.internal_format,
    272       info.width, info.height, info.depth, info.border,
    273       info.format, info.type, info.image.get() != NULL,
    274       CanRender(feature_info), CanRenderTo(), npot_,
    275       min_filter_, mag_filter_, wrap_s_, wrap_t_,
    276       usage_);
    277 }
    278 
    279 void Texture::SetMailboxManager(MailboxManager* mailbox_manager) {
    280   DCHECK(!mailbox_manager_ || mailbox_manager_ == mailbox_manager);
    281   mailbox_manager_ = mailbox_manager;
    282 }
    283 
    284 bool Texture::MarkMipmapsGenerated(
    285     const FeatureInfo* feature_info) {
    286   if (!CanGenerateMipmaps(feature_info)) {
    287     return false;
    288   }
    289   for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
    290     const Texture::LevelInfo& info1 = level_infos_[ii][0];
    291     GLsizei width = info1.width;
    292     GLsizei height = info1.height;
    293     GLsizei depth = info1.depth;
    294     GLenum target = target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D :
    295                                FaceIndexToGLTarget(ii);
    296     int num_mips = TextureManager::ComputeMipMapCount(width, height, depth);
    297     for (int level = 1; level < num_mips; ++level) {
    298       width = std::max(1, width >> 1);
    299       height = std::max(1, height >> 1);
    300       depth = std::max(1, depth >> 1);
    301       SetLevelInfo(feature_info,
    302                    target,
    303                    level,
    304                    info1.internal_format,
    305                    width,
    306                    height,
    307                    depth,
    308                    info1.border,
    309                    info1.format,
    310                    info1.type,
    311                    true);
    312     }
    313   }
    314 
    315   return true;
    316 }
    317 
    318 void Texture::SetTarget(
    319     const FeatureInfo* feature_info, GLenum target, GLint max_levels) {
    320   DCHECK_EQ(0u, target_);  // you can only set this once.
    321   target_ = target;
    322   size_t num_faces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
    323   level_infos_.resize(num_faces);
    324   for (size_t ii = 0; ii < num_faces; ++ii) {
    325     level_infos_[ii].resize(max_levels);
    326   }
    327 
    328   if (target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ARB) {
    329     min_filter_ = GL_LINEAR;
    330     wrap_s_ = wrap_t_ = GL_CLAMP_TO_EDGE;
    331   }
    332 
    333   if (target == GL_TEXTURE_EXTERNAL_OES) {
    334     immutable_ = true;
    335   }
    336   Update(feature_info);
    337   UpdateCanRenderCondition();
    338 }
    339 
    340 bool Texture::CanGenerateMipmaps(
    341     const FeatureInfo* feature_info) const {
    342   if ((npot() && !feature_info->feature_flags().npot_ok) ||
    343       level_infos_.empty() ||
    344       target_ == GL_TEXTURE_EXTERNAL_OES ||
    345       target_ == GL_TEXTURE_RECTANGLE_ARB) {
    346     return false;
    347   }
    348 
    349   // Can't generate mips for depth or stencil textures.
    350   const Texture::LevelInfo& first = level_infos_[0][0];
    351   uint32 channels = GLES2Util::GetChannelsForFormat(first.format);
    352   if (channels & (GLES2Util::kDepth | GLES2Util::kStencil)) {
    353     return false;
    354   }
    355 
    356   // TODO(gman): Check internal_format, format and type.
    357   for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
    358     const LevelInfo& info = level_infos_[ii][0];
    359     if ((info.target == 0) || (info.width != first.width) ||
    360         (info.height != first.height) || (info.depth != 1) ||
    361         (info.format != first.format) ||
    362         (info.internal_format != first.internal_format) ||
    363         (info.type != first.type) ||
    364         feature_info->validators()->compressed_texture_format.IsValid(
    365             info.internal_format) ||
    366         info.image.get()) {
    367       return false;
    368     }
    369   }
    370   return true;
    371 }
    372 
    373 void Texture::SetLevelCleared(GLenum target, GLint level, bool cleared) {
    374   DCHECK_GE(level, 0);
    375   DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
    376             level_infos_.size());
    377   DCHECK_LT(static_cast<size_t>(level),
    378             level_infos_[GLTargetToFaceIndex(target)].size());
    379   Texture::LevelInfo& info =
    380       level_infos_[GLTargetToFaceIndex(target)][level];
    381   UpdateMipCleared(&info, cleared);
    382   UpdateCleared();
    383 }
    384 
    385 void Texture::UpdateCleared() {
    386   if (level_infos_.empty()) {
    387     return;
    388   }
    389 
    390   const Texture::LevelInfo& first_face = level_infos_[0][0];
    391   int levels_needed = TextureManager::ComputeMipMapCount(
    392       first_face.width, first_face.height, first_face.depth);
    393   bool cleared = true;
    394   for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
    395     for (GLint jj = 0; jj < levels_needed; ++jj) {
    396       const Texture::LevelInfo& info = level_infos_[ii][jj];
    397       if (info.width > 0 && info.height > 0 && info.depth > 0 &&
    398           !info.cleared) {
    399         cleared = false;
    400         break;
    401       }
    402     }
    403   }
    404   UpdateSafeToRenderFrom(cleared);
    405 }
    406 
    407 void Texture::UpdateSafeToRenderFrom(bool cleared) {
    408   if (cleared_ == cleared)
    409     return;
    410   cleared_ = cleared;
    411   int delta = cleared ? -1 : +1;
    412   for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
    413     (*it)->manager()->UpdateSafeToRenderFrom(delta);
    414 }
    415 
    416 void Texture::UpdateMipCleared(LevelInfo* info, bool cleared) {
    417   if (info->cleared == cleared)
    418     return;
    419   info->cleared = cleared;
    420   int delta = cleared ? -1 : +1;
    421   num_uncleared_mips_ += delta;
    422   for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
    423     (*it)->manager()->UpdateUnclearedMips(delta);
    424 }
    425 
    426 void Texture::UpdateCanRenderCondition() {
    427   CanRenderCondition can_render_condition = GetCanRenderCondition();
    428   if (can_render_condition_ == can_render_condition)
    429     return;
    430   for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
    431     (*it)->manager()->UpdateCanRenderCondition(can_render_condition_,
    432                                                can_render_condition);
    433   can_render_condition_ = can_render_condition;
    434 }
    435 
    436 void Texture::IncAllFramebufferStateChangeCount() {
    437   for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
    438     (*it)->manager()->IncFramebufferStateChangeCount();
    439 }
    440 
    441 void Texture::SetLevelInfo(
    442     const FeatureInfo* feature_info,
    443     GLenum target,
    444     GLint level,
    445     GLenum internal_format,
    446     GLsizei width,
    447     GLsizei height,
    448     GLsizei depth,
    449     GLint border,
    450     GLenum format,
    451     GLenum type,
    452     bool cleared) {
    453   DCHECK_GE(level, 0);
    454   DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
    455             level_infos_.size());
    456   DCHECK_LT(static_cast<size_t>(level),
    457             level_infos_[GLTargetToFaceIndex(target)].size());
    458   DCHECK_GE(width, 0);
    459   DCHECK_GE(height, 0);
    460   DCHECK_GE(depth, 0);
    461   Texture::LevelInfo& info =
    462       level_infos_[GLTargetToFaceIndex(target)][level];
    463   info.target = target;
    464   info.level = level;
    465   info.internal_format = internal_format;
    466   info.width = width;
    467   info.height = height;
    468   info.depth = depth;
    469   info.border = border;
    470   info.format = format;
    471   info.type = type;
    472   info.image = 0;
    473 
    474   estimated_size_ -= info.estimated_size;
    475   GLES2Util::ComputeImageDataSizes(
    476       width, height, format, type, 4, &info.estimated_size, NULL, NULL);
    477   estimated_size_ += info.estimated_size;
    478 
    479   UpdateMipCleared(&info, cleared);
    480   max_level_set_ = std::max(max_level_set_, level);
    481   Update(feature_info);
    482   UpdateCleared();
    483   UpdateCanRenderCondition();
    484   if (IsAttachedToFramebuffer()) {
    485     // TODO(gman): If textures tracked which framebuffers they were attached to
    486     // we could just mark those framebuffers as not complete.
    487     IncAllFramebufferStateChangeCount();
    488   }
    489 }
    490 
    491 bool Texture::ValidForTexture(
    492     GLint target,
    493     GLint level,
    494     GLint xoffset,
    495     GLint yoffset,
    496     GLsizei width,
    497     GLsizei height,
    498     GLenum format,
    499     GLenum type) const {
    500   size_t face_index = GLTargetToFaceIndex(target);
    501   if (level >= 0 && face_index < level_infos_.size() &&
    502       static_cast<size_t>(level) < level_infos_[face_index].size()) {
    503     const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
    504     int32 right;
    505     int32 top;
    506     return SafeAddInt32(xoffset, width, &right) &&
    507            SafeAddInt32(yoffset, height, &top) &&
    508            xoffset >= 0 &&
    509            yoffset >= 0 &&
    510            right <= info.width &&
    511            top <= info.height &&
    512            format == info.internal_format &&
    513            type == info.type;
    514   }
    515   return false;
    516 }
    517 
    518 bool Texture::GetLevelSize(
    519     GLint target, GLint level, GLsizei* width, GLsizei* height) const {
    520   DCHECK(width);
    521   DCHECK(height);
    522   size_t face_index = GLTargetToFaceIndex(target);
    523   if (level >= 0 && face_index < level_infos_.size() &&
    524       static_cast<size_t>(level) < level_infos_[face_index].size()) {
    525     const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
    526     if (info.target != 0) {
    527       *width = info.width;
    528       *height = info.height;
    529       return true;
    530     }
    531   }
    532   return false;
    533 }
    534 
    535 bool Texture::GetLevelType(
    536     GLint target, GLint level, GLenum* type, GLenum* internal_format) const {
    537   DCHECK(type);
    538   DCHECK(internal_format);
    539   size_t face_index = GLTargetToFaceIndex(target);
    540   if (level >= 0 && face_index < level_infos_.size() &&
    541       static_cast<size_t>(level) < level_infos_[face_index].size()) {
    542     const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
    543     if (info.target != 0) {
    544       *type = info.type;
    545       *internal_format = info.internal_format;
    546       return true;
    547     }
    548   }
    549   return false;
    550 }
    551 
    552 GLenum Texture::SetParameter(
    553     const FeatureInfo* feature_info, GLenum pname, GLint param) {
    554   DCHECK(feature_info);
    555 
    556   if (target_ == GL_TEXTURE_EXTERNAL_OES ||
    557       target_ == GL_TEXTURE_RECTANGLE_ARB) {
    558     if (pname == GL_TEXTURE_MIN_FILTER &&
    559         (param != GL_NEAREST && param != GL_LINEAR))
    560       return GL_INVALID_ENUM;
    561     if ((pname == GL_TEXTURE_WRAP_S || pname == GL_TEXTURE_WRAP_T) &&
    562         param != GL_CLAMP_TO_EDGE)
    563       return GL_INVALID_ENUM;
    564   }
    565 
    566   switch (pname) {
    567     case GL_TEXTURE_MIN_FILTER:
    568       if (!feature_info->validators()->texture_min_filter_mode.IsValid(param)) {
    569         return GL_INVALID_ENUM;
    570       }
    571       min_filter_ = param;
    572       break;
    573     case GL_TEXTURE_MAG_FILTER:
    574       if (!feature_info->validators()->texture_mag_filter_mode.IsValid(param)) {
    575         return GL_INVALID_ENUM;
    576       }
    577       mag_filter_ = param;
    578       break;
    579     case GL_TEXTURE_POOL_CHROMIUM:
    580       if (!feature_info->validators()->texture_pool.IsValid(param)) {
    581         return GL_INVALID_ENUM;
    582       }
    583       GetMemTracker()->TrackMemFree(estimated_size());
    584       pool_ = param;
    585       GetMemTracker()->TrackMemAlloc(estimated_size());
    586       break;
    587     case GL_TEXTURE_WRAP_S:
    588       if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
    589         return GL_INVALID_ENUM;
    590       }
    591       wrap_s_ = param;
    592       break;
    593     case GL_TEXTURE_WRAP_T:
    594       if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
    595         return GL_INVALID_ENUM;
    596       }
    597       wrap_t_ = param;
    598       break;
    599     case GL_TEXTURE_MAX_ANISOTROPY_EXT:
    600       if (param < 1) {
    601         return GL_INVALID_VALUE;
    602       }
    603       break;
    604     case GL_TEXTURE_USAGE_ANGLE:
    605       if (!feature_info->validators()->texture_usage.IsValid(param)) {
    606         return GL_INVALID_ENUM;
    607       }
    608       usage_ = param;
    609       break;
    610     default:
    611       NOTREACHED();
    612       return GL_INVALID_ENUM;
    613   }
    614   Update(feature_info);
    615   UpdateCleared();
    616   UpdateCanRenderCondition();
    617   return GL_NO_ERROR;
    618 }
    619 
    620 void Texture::Update(const FeatureInfo* feature_info) {
    621   // Update npot status.
    622   // Assume GL_TEXTURE_EXTERNAL_OES textures are npot, all others
    623   npot_ = target_ == GL_TEXTURE_EXTERNAL_OES;
    624 
    625   if (level_infos_.empty()) {
    626     texture_complete_ = false;
    627     cube_complete_ = false;
    628     return;
    629   }
    630 
    631   // checks that the first mip of any face is npot.
    632   for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
    633     const Texture::LevelInfo& info = level_infos_[ii][0];
    634     if (GLES2Util::IsNPOT(info.width) ||
    635         GLES2Util::IsNPOT(info.height) ||
    636         GLES2Util::IsNPOT(info.depth)) {
    637       npot_ = true;
    638       break;
    639     }
    640   }
    641 
    642   // Update texture_complete and cube_complete status.
    643   const Texture::LevelInfo& first_face = level_infos_[0][0];
    644   int levels_needed = TextureManager::ComputeMipMapCount(
    645       first_face.width, first_face.height, first_face.depth);
    646   texture_complete_ =
    647       max_level_set_ >= (levels_needed - 1) && max_level_set_ >= 0;
    648   cube_complete_ = (level_infos_.size() == 6) &&
    649                    (first_face.width == first_face.height);
    650 
    651   if (first_face.width == 0 || first_face.height == 0) {
    652     texture_complete_ = false;
    653   }
    654   if (first_face.type == GL_FLOAT &&
    655       !feature_info->feature_flags().enable_texture_float_linear &&
    656       (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
    657        mag_filter_ != GL_NEAREST)) {
    658     texture_complete_ = false;
    659   } else if (first_face.type == GL_HALF_FLOAT_OES &&
    660              !feature_info->feature_flags().enable_texture_half_float_linear &&
    661              (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
    662               mag_filter_ != GL_NEAREST)) {
    663     texture_complete_ = false;
    664   }
    665   for (size_t ii = 0;
    666        ii < level_infos_.size() && (cube_complete_ || texture_complete_);
    667        ++ii) {
    668     const Texture::LevelInfo& level0 = level_infos_[ii][0];
    669     if (level0.target == 0 ||
    670         level0.width != first_face.width ||
    671         level0.height != first_face.height ||
    672         level0.depth != 1 ||
    673         level0.internal_format != first_face.internal_format ||
    674         level0.format != first_face.format ||
    675         level0.type != first_face.type) {
    676       cube_complete_ = false;
    677     }
    678     // Get level0 dimensions
    679     GLsizei width = level0.width;
    680     GLsizei height = level0.height;
    681     GLsizei depth = level0.depth;
    682     for (GLint jj = 1; jj < levels_needed; ++jj) {
    683       // compute required size for mip.
    684       width = std::max(1, width >> 1);
    685       height = std::max(1, height >> 1);
    686       depth = std::max(1, depth >> 1);
    687       const Texture::LevelInfo& info = level_infos_[ii][jj];
    688       if (info.target == 0 ||
    689           info.width != width ||
    690           info.height != height ||
    691           info.depth != depth ||
    692           info.internal_format != level0.internal_format ||
    693           info.format != level0.format ||
    694           info.type != level0.type) {
    695         texture_complete_ = false;
    696         break;
    697       }
    698     }
    699   }
    700 }
    701 
    702 bool Texture::ClearRenderableLevels(GLES2Decoder* decoder) {
    703   DCHECK(decoder);
    704   if (cleared_) {
    705     return true;
    706   }
    707 
    708   const Texture::LevelInfo& first_face = level_infos_[0][0];
    709   int levels_needed = TextureManager::ComputeMipMapCount(
    710       first_face.width, first_face.height, first_face.depth);
    711 
    712   for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
    713     for (GLint jj = 0; jj < levels_needed; ++jj) {
    714       Texture::LevelInfo& info = level_infos_[ii][jj];
    715       if (info.target != 0) {
    716         if (!ClearLevel(decoder, info.target, jj)) {
    717           return false;
    718         }
    719       }
    720     }
    721   }
    722   UpdateSafeToRenderFrom(true);
    723   return true;
    724 }
    725 
    726 bool Texture::IsLevelCleared(GLenum target, GLint level) const {
    727   size_t face_index = GLTargetToFaceIndex(target);
    728   if (face_index >= level_infos_.size() ||
    729       level >= static_cast<GLint>(level_infos_[face_index].size())) {
    730     return true;
    731   }
    732 
    733   const Texture::LevelInfo& info = level_infos_[face_index][level];
    734 
    735   return info.cleared;
    736 }
    737 
    738 bool Texture::ClearLevel(
    739     GLES2Decoder* decoder, GLenum target, GLint level) {
    740   DCHECK(decoder);
    741   size_t face_index = GLTargetToFaceIndex(target);
    742   if (face_index >= level_infos_.size() ||
    743       level >= static_cast<GLint>(level_infos_[face_index].size())) {
    744     return true;
    745   }
    746 
    747   Texture::LevelInfo& info = level_infos_[face_index][level];
    748 
    749   DCHECK(target == info.target);
    750 
    751   if (info.target == 0 ||
    752       info.cleared ||
    753       info.width == 0 ||
    754       info.height == 0 ||
    755       info.depth == 0) {
    756     return true;
    757   }
    758 
    759   // NOTE: It seems kind of gross to call back into the decoder for this
    760   // but only the decoder knows all the state (like unpack_alignment_) that's
    761   // needed to be able to call GL correctly.
    762   bool cleared = decoder->ClearLevel(
    763       service_id_, target_, info.target, info.level, info.format, info.type,
    764       info.width, info.height, immutable_);
    765   UpdateMipCleared(&info, cleared);
    766   return info.cleared;
    767 }
    768 
    769 void Texture::SetLevelImage(
    770     const FeatureInfo* feature_info,
    771     GLenum target,
    772     GLint level,
    773     gfx::GLImage* image) {
    774   DCHECK_GE(level, 0);
    775   DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
    776             level_infos_.size());
    777   DCHECK_LT(static_cast<size_t>(level),
    778             level_infos_[GLTargetToFaceIndex(target)].size());
    779   Texture::LevelInfo& info =
    780       level_infos_[GLTargetToFaceIndex(target)][level];
    781   DCHECK_EQ(info.target, target);
    782   DCHECK_EQ(info.level, level);
    783   info.image = image;
    784   UpdateCanRenderCondition();
    785 }
    786 
    787 gfx::GLImage* Texture::GetLevelImage(
    788   GLint target, GLint level) const {
    789   size_t face_index = GLTargetToFaceIndex(target);
    790   if (level >= 0 && face_index < level_infos_.size() &&
    791       static_cast<size_t>(level) < level_infos_[face_index].size()) {
    792     const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
    793     if (info.target != 0) {
    794       return info.image.get();
    795     }
    796   }
    797   return 0;
    798 }
    799 
    800 
    801 TextureRef::TextureRef(TextureManager* manager,
    802                        GLuint client_id,
    803                        Texture* texture)
    804     : manager_(manager),
    805       texture_(texture),
    806       client_id_(client_id),
    807       is_stream_texture_owner_(false) {
    808   DCHECK(manager_);
    809   DCHECK(texture_);
    810   texture_->AddTextureRef(this);
    811   manager_->StartTracking(this);
    812 }
    813 
    814 scoped_refptr<TextureRef> TextureRef::Create(TextureManager* manager,
    815                                              GLuint client_id,
    816                                              GLuint service_id) {
    817   return new TextureRef(manager, client_id, new Texture(service_id));
    818 }
    819 
    820 TextureRef::~TextureRef() {
    821   manager_->StopTracking(this);
    822   texture_->RemoveTextureRef(this, manager_->have_context_);
    823   manager_ = NULL;
    824 }
    825 
    826 TextureManager::TextureManager(
    827     MemoryTracker* memory_tracker,
    828     FeatureInfo* feature_info,
    829     GLint max_texture_size,
    830     GLint max_cube_map_texture_size)
    831     : memory_tracker_managed_(
    832           new MemoryTypeTracker(memory_tracker, MemoryTracker::kManaged)),
    833       memory_tracker_unmanaged_(
    834           new MemoryTypeTracker(memory_tracker, MemoryTracker::kUnmanaged)),
    835       feature_info_(feature_info),
    836       framebuffer_manager_(NULL),
    837       stream_texture_manager_(NULL),
    838       max_texture_size_(max_texture_size),
    839       max_cube_map_texture_size_(max_cube_map_texture_size),
    840       max_levels_(ComputeMipMapCount(max_texture_size,
    841                                      max_texture_size,
    842                                      max_texture_size)),
    843       max_cube_map_levels_(ComputeMipMapCount(max_cube_map_texture_size,
    844                                               max_cube_map_texture_size,
    845                                               max_cube_map_texture_size)),
    846       num_unrenderable_textures_(0),
    847       num_unsafe_textures_(0),
    848       num_uncleared_mips_(0),
    849       texture_count_(0),
    850       have_context_(true) {
    851   for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
    852     black_texture_ids_[ii] = 0;
    853   }
    854 }
    855 
    856 bool TextureManager::Initialize() {
    857   // TODO(gman): The default textures have to be real textures, not the 0
    858   // texture because we simulate non shared resources on top of shared
    859   // resources and all contexts that share resource share the same default
    860   // texture.
    861   default_textures_[kTexture2D] = CreateDefaultAndBlackTextures(
    862       GL_TEXTURE_2D, &black_texture_ids_[kTexture2D]);
    863   default_textures_[kCubeMap] = CreateDefaultAndBlackTextures(
    864       GL_TEXTURE_CUBE_MAP, &black_texture_ids_[kCubeMap]);
    865 
    866   if (feature_info_->feature_flags().oes_egl_image_external) {
    867     default_textures_[kExternalOES] = CreateDefaultAndBlackTextures(
    868         GL_TEXTURE_EXTERNAL_OES, &black_texture_ids_[kExternalOES]);
    869   }
    870 
    871   if (feature_info_->feature_flags().arb_texture_rectangle) {
    872     default_textures_[kRectangleARB] = CreateDefaultAndBlackTextures(
    873         GL_TEXTURE_RECTANGLE_ARB, &black_texture_ids_[kRectangleARB]);
    874   }
    875 
    876   return true;
    877 }
    878 
    879 scoped_refptr<TextureRef>
    880     TextureManager::CreateDefaultAndBlackTextures(
    881         GLenum target,
    882         GLuint* black_texture) {
    883   static uint8 black[] = {0, 0, 0, 255};
    884 
    885   // Sampling a texture not associated with any EGLImage sibling will return
    886   // black values according to the spec.
    887   bool needs_initialization = (target != GL_TEXTURE_EXTERNAL_OES);
    888   bool needs_faces = (target == GL_TEXTURE_CUBE_MAP);
    889 
    890   // Make default textures and texture for replacing non-renderable textures.
    891   GLuint ids[2];
    892   glGenTextures(arraysize(ids), ids);
    893   for (unsigned long ii = 0; ii < arraysize(ids); ++ii) {
    894     glBindTexture(target, ids[ii]);
    895     if (needs_initialization) {
    896       if (needs_faces) {
    897         for (int jj = 0; jj < GLES2Util::kNumFaces; ++jj) {
    898           glTexImage2D(GLES2Util::IndexToGLFaceTarget(jj), 0, GL_RGBA, 1, 1, 0,
    899                        GL_RGBA, GL_UNSIGNED_BYTE, black);
    900         }
    901       } else {
    902         glTexImage2D(target, 0, GL_RGBA, 1, 1, 0, GL_RGBA,
    903                      GL_UNSIGNED_BYTE, black);
    904       }
    905     }
    906   }
    907   glBindTexture(target, 0);
    908 
    909   scoped_refptr<TextureRef> default_texture(
    910       TextureRef::Create(this, 0, ids[1]));
    911   SetTarget(default_texture.get(), target);
    912   if (needs_faces) {
    913     for (int ii = 0; ii < GLES2Util::kNumFaces; ++ii) {
    914       SetLevelInfo(default_texture.get(),
    915                    GLES2Util::IndexToGLFaceTarget(ii),
    916                    0,
    917                    GL_RGBA,
    918                    1,
    919                    1,
    920                    1,
    921                    0,
    922                    GL_RGBA,
    923                    GL_UNSIGNED_BYTE,
    924                    true);
    925     }
    926   } else {
    927     if (needs_initialization) {
    928       SetLevelInfo(default_texture.get(),
    929                    GL_TEXTURE_2D,
    930                    0,
    931                    GL_RGBA,
    932                    1,
    933                    1,
    934                    1,
    935                    0,
    936                    GL_RGBA,
    937                    GL_UNSIGNED_BYTE,
    938                    true);
    939     } else {
    940       SetLevelInfo(default_texture.get(),
    941                    GL_TEXTURE_EXTERNAL_OES,
    942                    0,
    943                    GL_RGBA,
    944                    1,
    945                    1,
    946                    1,
    947                    0,
    948                    GL_RGBA,
    949                    GL_UNSIGNED_BYTE,
    950                    true);
    951     }
    952   }
    953 
    954   *black_texture = ids[0];
    955   return default_texture;
    956 }
    957 
    958 bool TextureManager::ValidForTarget(
    959     GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth) {
    960   GLsizei max_size = MaxSizeForTarget(target) >> level;
    961   return level >= 0 &&
    962          width >= 0 &&
    963          height >= 0 &&
    964          depth >= 0 &&
    965          level < MaxLevelsForTarget(target) &&
    966          width <= max_size &&
    967          height <= max_size &&
    968          depth <= max_size &&
    969          (level == 0 || feature_info_->feature_flags().npot_ok ||
    970           (!GLES2Util::IsNPOT(width) &&
    971            !GLES2Util::IsNPOT(height) &&
    972            !GLES2Util::IsNPOT(depth))) &&
    973          (target != GL_TEXTURE_CUBE_MAP || (width == height && depth == 1)) &&
    974          (target != GL_TEXTURE_2D || (depth == 1));
    975 }
    976 
    977 void TextureManager::SetTarget(TextureRef* ref, GLenum target) {
    978   DCHECK(ref);
    979   ref->texture()
    980       ->SetTarget(feature_info_.get(), target, MaxLevelsForTarget(target));
    981 }
    982 
    983 void TextureManager::SetStreamTexture(TextureRef* ref, bool stream_texture) {
    984   DCHECK(ref);
    985   // Only the owner can mark as non-stream texture.
    986   DCHECK_EQ(stream_texture, !ref->is_stream_texture_owner_);
    987   ref->texture()->SetStreamTexture(stream_texture);
    988   ref->set_is_stream_texture_owner(stream_texture);
    989 }
    990 
    991 bool TextureManager::IsStreamTextureOwner(TextureRef* ref) {
    992   DCHECK(ref);
    993   return ref->is_stream_texture_owner();
    994 }
    995 
    996 void TextureManager::SetLevelCleared(TextureRef* ref,
    997                                      GLenum target,
    998                                      GLint level,
    999                                      bool cleared) {
   1000   DCHECK(ref);
   1001   ref->texture()->SetLevelCleared(target, level, cleared);
   1002 }
   1003 
   1004 bool TextureManager::ClearRenderableLevels(
   1005     GLES2Decoder* decoder, TextureRef* ref) {
   1006   DCHECK(ref);
   1007   return ref->texture()->ClearRenderableLevels(decoder);
   1008 }
   1009 
   1010 bool TextureManager::ClearTextureLevel(
   1011     GLES2Decoder* decoder, TextureRef* ref,
   1012     GLenum target, GLint level) {
   1013   DCHECK(ref);
   1014   Texture* texture = ref->texture();
   1015   if (texture->num_uncleared_mips() == 0) {
   1016     return true;
   1017   }
   1018   bool result = texture->ClearLevel(decoder, target, level);
   1019   texture->UpdateCleared();
   1020   return result;
   1021 }
   1022 
   1023 void TextureManager::SetLevelInfo(
   1024     TextureRef* ref,
   1025     GLenum target,
   1026     GLint level,
   1027     GLenum internal_format,
   1028     GLsizei width,
   1029     GLsizei height,
   1030     GLsizei depth,
   1031     GLint border,
   1032     GLenum format,
   1033     GLenum type,
   1034     bool cleared) {
   1035   DCHECK(ref);
   1036   Texture* texture = ref->texture();
   1037 
   1038   texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
   1039   texture->SetLevelInfo(feature_info_.get(),
   1040                         target,
   1041                         level,
   1042                         internal_format,
   1043                         width,
   1044                         height,
   1045                         depth,
   1046                         border,
   1047                         format,
   1048                         type,
   1049                         cleared);
   1050   texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
   1051 }
   1052 
   1053 Texture* TextureManager::Produce(TextureRef* ref) {
   1054   DCHECK(ref);
   1055   return ref->texture();
   1056 }
   1057 
   1058 TextureRef* TextureManager::Consume(
   1059     GLuint client_id,
   1060     Texture* texture) {
   1061   DCHECK(client_id);
   1062   scoped_refptr<TextureRef> ref(new TextureRef(this, client_id, texture));
   1063   bool result = textures_.insert(std::make_pair(client_id, ref)).second;
   1064   DCHECK(result);
   1065   return ref.get();
   1066 }
   1067 
   1068 void TextureManager::SetParameter(
   1069     const char* function_name, ErrorState* error_state,
   1070     TextureRef* ref, GLenum pname, GLint param) {
   1071   DCHECK(error_state);
   1072   DCHECK(ref);
   1073   Texture* texture = ref->texture();
   1074   GLenum result = texture->SetParameter(feature_info_.get(), pname, param);
   1075   if (result != GL_NO_ERROR) {
   1076     if (result == GL_INVALID_ENUM) {
   1077       ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
   1078           error_state, function_name, param, "param");
   1079     } else {
   1080       ERRORSTATE_SET_GL_ERROR_INVALID_PARAM(
   1081           error_state, result, function_name, pname, static_cast<GLint>(param));
   1082     }
   1083   } else {
   1084     // Texture tracking pools exist only for the command decoder, so
   1085     // do not pass them on to the native GL implementation.
   1086     if (pname != GL_TEXTURE_POOL_CHROMIUM) {
   1087       glTexParameteri(texture->target(), pname, param);
   1088     }
   1089   }
   1090 }
   1091 
   1092 bool TextureManager::MarkMipmapsGenerated(TextureRef* ref) {
   1093   DCHECK(ref);
   1094   Texture* texture = ref->texture();
   1095   texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
   1096   bool result = texture->MarkMipmapsGenerated(feature_info_.get());
   1097   texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
   1098   return result;
   1099 }
   1100 
   1101 TextureRef* TextureManager::CreateTexture(
   1102     GLuint client_id, GLuint service_id) {
   1103   DCHECK_NE(0u, service_id);
   1104   scoped_refptr<TextureRef> ref(TextureRef::Create(
   1105       this, client_id, service_id));
   1106   std::pair<TextureMap::iterator, bool> result =
   1107       textures_.insert(std::make_pair(client_id, ref));
   1108   DCHECK(result.second);
   1109   return ref.get();
   1110 }
   1111 
   1112 TextureRef* TextureManager::GetTexture(
   1113     GLuint client_id) const {
   1114   TextureMap::const_iterator it = textures_.find(client_id);
   1115   return it != textures_.end() ? it->second.get() : NULL;
   1116 }
   1117 
   1118 void TextureManager::RemoveTexture(GLuint client_id) {
   1119   TextureMap::iterator it = textures_.find(client_id);
   1120   if (it != textures_.end()) {
   1121     it->second->reset_client_id();
   1122     textures_.erase(it);
   1123   }
   1124 }
   1125 
   1126 void TextureManager::StartTracking(TextureRef* ref) {
   1127   Texture* texture = ref->texture();
   1128   ++texture_count_;
   1129   num_uncleared_mips_ += texture->num_uncleared_mips();
   1130   if (!texture->SafeToRenderFrom())
   1131     ++num_unsafe_textures_;
   1132   if (!texture->CanRender(feature_info_.get()))
   1133     ++num_unrenderable_textures_;
   1134 }
   1135 
   1136 void TextureManager::StopTracking(TextureRef* ref) {
   1137   FOR_EACH_OBSERVER(DestructionObserver,
   1138                     destruction_observers_,
   1139                     OnTextureRefDestroying(ref));
   1140 
   1141   Texture* texture = ref->texture();
   1142   if (ref->is_stream_texture_owner_ && stream_texture_manager_) {
   1143     DCHECK(texture->IsStreamTexture());
   1144     stream_texture_manager_->DestroyStreamTexture(texture->service_id());
   1145   }
   1146 
   1147   --texture_count_;
   1148   if (!texture->CanRender(feature_info_.get())) {
   1149     DCHECK_NE(0, num_unrenderable_textures_);
   1150     --num_unrenderable_textures_;
   1151   }
   1152   if (!texture->SafeToRenderFrom()) {
   1153     DCHECK_NE(0, num_unsafe_textures_);
   1154     --num_unsafe_textures_;
   1155   }
   1156   num_uncleared_mips_ -= texture->num_uncleared_mips();
   1157   DCHECK_GE(num_uncleared_mips_, 0);
   1158 }
   1159 
   1160 MemoryTypeTracker* TextureManager::GetMemTracker(GLenum tracking_pool) {
   1161   switch(tracking_pool) {
   1162     case GL_TEXTURE_POOL_MANAGED_CHROMIUM:
   1163       return memory_tracker_managed_.get();
   1164       break;
   1165     case GL_TEXTURE_POOL_UNMANAGED_CHROMIUM:
   1166       return memory_tracker_unmanaged_.get();
   1167       break;
   1168     default:
   1169       break;
   1170   }
   1171   NOTREACHED();
   1172   return NULL;
   1173 }
   1174 
   1175 Texture* TextureManager::GetTextureForServiceId(GLuint service_id) const {
   1176   // This doesn't need to be fast. It's only used during slow queries.
   1177   for (TextureMap::const_iterator it = textures_.begin();
   1178        it != textures_.end(); ++it) {
   1179     Texture* texture = it->second->texture();
   1180     if (texture->service_id() == service_id)
   1181       return texture;
   1182   }
   1183   return NULL;
   1184 }
   1185 
   1186 GLsizei TextureManager::ComputeMipMapCount(
   1187     GLsizei width, GLsizei height, GLsizei depth) {
   1188   return 1 + base::bits::Log2Floor(std::max(std::max(width, height), depth));
   1189 }
   1190 
   1191 void TextureManager::SetLevelImage(
   1192     TextureRef* ref,
   1193     GLenum target,
   1194     GLint level,
   1195     gfx::GLImage* image) {
   1196   DCHECK(ref);
   1197   ref->texture()->SetLevelImage(feature_info_.get(), target, level, image);
   1198 }
   1199 
   1200 void TextureManager::AddToSignature(
   1201     TextureRef* ref,
   1202     GLenum target,
   1203     GLint level,
   1204     std::string* signature) const {
   1205   ref->texture()->AddToSignature(feature_info_.get(), target, level, signature);
   1206 }
   1207 
   1208 void TextureManager::UpdateSafeToRenderFrom(int delta) {
   1209   num_unsafe_textures_ += delta;
   1210   DCHECK_GE(num_unsafe_textures_, 0);
   1211 }
   1212 
   1213 void TextureManager::UpdateUnclearedMips(int delta) {
   1214   num_uncleared_mips_ += delta;
   1215   DCHECK_GE(num_uncleared_mips_, 0);
   1216 }
   1217 
   1218 void TextureManager::UpdateCanRenderCondition(
   1219     Texture::CanRenderCondition old_condition,
   1220     Texture::CanRenderCondition new_condition) {
   1221   if (old_condition == Texture::CAN_RENDER_NEVER ||
   1222       (old_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
   1223        !feature_info_->feature_flags().npot_ok)) {
   1224     DCHECK_GT(num_unrenderable_textures_, 0);
   1225     --num_unrenderable_textures_;
   1226   }
   1227   if (new_condition == Texture::CAN_RENDER_NEVER ||
   1228       (new_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
   1229        !feature_info_->feature_flags().npot_ok))
   1230     ++num_unrenderable_textures_;
   1231 }
   1232 
   1233 void TextureManager::IncFramebufferStateChangeCount() {
   1234   if (framebuffer_manager_)
   1235     framebuffer_manager_->IncFramebufferStateChangeCount();
   1236 
   1237 }
   1238 
   1239 }  // namespace gles2
   1240 }  // namespace gpu
   1241