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/framebuffer_manager.h"
      6 #include "base/logging.h"
      7 #include "base/strings/stringprintf.h"
      8 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
      9 #include "gpu/command_buffer/service/renderbuffer_manager.h"
     10 #include "gpu/command_buffer/service/texture_manager.h"
     11 #include "ui/gl/gl_bindings.h"
     12 
     13 namespace gpu {
     14 namespace gles2 {
     15 
     16 DecoderFramebufferState::DecoderFramebufferState()
     17     : clear_state_dirty(false),
     18       bound_read_framebuffer(NULL),
     19       bound_draw_framebuffer(NULL) {
     20 }
     21 
     22 DecoderFramebufferState::~DecoderFramebufferState() {
     23 }
     24 
     25 Framebuffer::FramebufferComboCompleteMap*
     26     Framebuffer::framebuffer_combo_complete_map_;
     27 
     28 // Framebuffer completeness is not cacheable on OS X because of dynamic
     29 // graphics switching.
     30 // http://crbug.com/180876
     31 #if defined(OS_MACOSX)
     32 bool Framebuffer::allow_framebuffer_combo_complete_map_ = false;
     33 #else
     34 bool Framebuffer::allow_framebuffer_combo_complete_map_ = true;
     35 #endif
     36 
     37 void Framebuffer::ClearFramebufferCompleteComboMap() {
     38   if (framebuffer_combo_complete_map_) {
     39     framebuffer_combo_complete_map_->clear();
     40   }
     41 }
     42 
     43 class RenderbufferAttachment
     44     : public Framebuffer::Attachment {
     45  public:
     46   explicit RenderbufferAttachment(
     47       Renderbuffer* renderbuffer)
     48       : renderbuffer_(renderbuffer) {
     49   }
     50 
     51   virtual GLsizei width() const OVERRIDE {
     52     return renderbuffer_->width();
     53   }
     54 
     55   virtual GLsizei height() const OVERRIDE {
     56     return renderbuffer_->height();
     57   }
     58 
     59   virtual GLenum internal_format() const OVERRIDE {
     60     return renderbuffer_->internal_format();
     61   }
     62 
     63   virtual GLenum texture_type() const OVERRIDE {
     64     return 0;
     65   }
     66 
     67   virtual GLsizei samples() const OVERRIDE {
     68     return renderbuffer_->samples();
     69   }
     70 
     71   virtual GLuint object_name() const OVERRIDE {
     72     return renderbuffer_->client_id();
     73   }
     74 
     75   virtual bool cleared() const OVERRIDE {
     76     return renderbuffer_->cleared();
     77   }
     78 
     79   virtual void SetCleared(
     80       RenderbufferManager* renderbuffer_manager,
     81       TextureManager* /* texture_manager */,
     82       bool cleared) OVERRIDE {
     83     renderbuffer_manager->SetCleared(renderbuffer_.get(), cleared);
     84   }
     85 
     86   virtual bool IsTexture(
     87       TextureRef* /* texture */) const OVERRIDE {
     88     return false;
     89   }
     90 
     91   virtual bool IsRenderbuffer(
     92        Renderbuffer* renderbuffer) const OVERRIDE {
     93     return renderbuffer_.get() == renderbuffer;
     94   }
     95 
     96   virtual bool CanRenderTo() const OVERRIDE {
     97     return true;
     98   }
     99 
    100   virtual void DetachFromFramebuffer(Framebuffer* framebuffer) const OVERRIDE {
    101     // Nothing to do for renderbuffers.
    102   }
    103 
    104   virtual bool ValidForAttachmentType(
    105       GLenum attachment_type, uint32 max_color_attachments) OVERRIDE {
    106     uint32 need = GLES2Util::GetChannelsNeededForAttachmentType(
    107         attachment_type, max_color_attachments);
    108     uint32 have = GLES2Util::GetChannelsForFormat(internal_format());
    109     return (need & have) != 0;
    110   }
    111 
    112   Renderbuffer* renderbuffer() const {
    113     return renderbuffer_.get();
    114   }
    115 
    116   virtual void AddToSignature(
    117       TextureManager* texture_manager, std::string* signature) const OVERRIDE {
    118     DCHECK(signature);
    119     renderbuffer_->AddToSignature(signature);
    120   }
    121 
    122   virtual void OnWillRenderTo() const OVERRIDE {}
    123   virtual void OnDidRenderTo() const OVERRIDE {}
    124 
    125  protected:
    126   virtual ~RenderbufferAttachment() { }
    127 
    128  private:
    129   scoped_refptr<Renderbuffer> renderbuffer_;
    130 
    131   DISALLOW_COPY_AND_ASSIGN(RenderbufferAttachment);
    132 };
    133 
    134 class TextureAttachment
    135     : public Framebuffer::Attachment {
    136  public:
    137   TextureAttachment(
    138       TextureRef* texture_ref, GLenum target, GLint level, GLsizei samples)
    139       : texture_ref_(texture_ref),
    140         target_(target),
    141         level_(level),
    142         samples_(samples) {
    143   }
    144 
    145   virtual GLsizei width() const OVERRIDE {
    146     GLsizei temp_width = 0;
    147     GLsizei temp_height = 0;
    148     texture_ref_->texture()->GetLevelSize(
    149         target_, level_, &temp_width, &temp_height);
    150     return temp_width;
    151   }
    152 
    153   virtual GLsizei height() const OVERRIDE {
    154     GLsizei temp_width = 0;
    155     GLsizei temp_height = 0;
    156     texture_ref_->texture()->GetLevelSize(
    157         target_, level_, &temp_width, &temp_height);
    158     return temp_height;
    159   }
    160 
    161   virtual GLenum internal_format() const OVERRIDE {
    162     GLenum temp_type = 0;
    163     GLenum temp_internal_format = 0;
    164     texture_ref_->texture()->GetLevelType(
    165         target_, level_, &temp_type, &temp_internal_format);
    166     return temp_internal_format;
    167   }
    168 
    169   virtual GLenum texture_type() const OVERRIDE {
    170     GLenum temp_type = 0;
    171     GLenum temp_internal_format = 0;
    172     texture_ref_->texture()->GetLevelType(
    173         target_, level_, &temp_type, &temp_internal_format);
    174     return temp_type;
    175   }
    176 
    177   virtual GLsizei samples() const OVERRIDE {
    178     return samples_;
    179   }
    180 
    181   virtual GLuint object_name() const OVERRIDE {
    182     return texture_ref_->client_id();
    183   }
    184 
    185   virtual bool cleared() const OVERRIDE {
    186     return texture_ref_->texture()->IsLevelCleared(target_, level_);
    187   }
    188 
    189   virtual void SetCleared(
    190       RenderbufferManager* /* renderbuffer_manager */,
    191       TextureManager* texture_manager,
    192       bool cleared) OVERRIDE {
    193     texture_manager->SetLevelCleared(
    194         texture_ref_.get(), target_, level_, cleared);
    195   }
    196 
    197   virtual bool IsTexture(TextureRef* texture) const OVERRIDE {
    198     return texture == texture_ref_.get();
    199   }
    200 
    201   virtual bool IsRenderbuffer(
    202        Renderbuffer* /* renderbuffer */)
    203           const OVERRIDE {
    204     return false;
    205   }
    206 
    207   TextureRef* texture() const {
    208     return texture_ref_.get();
    209   }
    210 
    211   virtual bool CanRenderTo() const OVERRIDE {
    212     return texture_ref_->texture()->CanRenderTo();
    213   }
    214 
    215   virtual void DetachFromFramebuffer(Framebuffer* framebuffer)
    216       const OVERRIDE {
    217     texture_ref_->texture()->DetachFromFramebuffer();
    218     framebuffer->OnTextureRefDetached(texture_ref_.get());
    219   }
    220 
    221   virtual bool ValidForAttachmentType(
    222       GLenum attachment_type, uint32 max_color_attachments) OVERRIDE {
    223     GLenum type = 0;
    224     GLenum internal_format = 0;
    225     if (!texture_ref_->texture()->GetLevelType(
    226         target_, level_, &type, &internal_format)) {
    227       return false;
    228     }
    229     uint32 need = GLES2Util::GetChannelsNeededForAttachmentType(
    230         attachment_type, max_color_attachments);
    231     uint32 have = GLES2Util::GetChannelsForFormat(internal_format);
    232 
    233     // Workaround for NVIDIA drivers that incorrectly expose these formats as
    234     // renderable:
    235     if (internal_format == GL_LUMINANCE || internal_format == GL_ALPHA ||
    236         internal_format == GL_LUMINANCE_ALPHA) {
    237       return false;
    238     }
    239     return (need & have) != 0;
    240   }
    241 
    242   virtual void AddToSignature(
    243       TextureManager* texture_manager, std::string* signature) const OVERRIDE {
    244     DCHECK(signature);
    245     texture_manager->AddToSignature(
    246         texture_ref_.get(), target_, level_, signature);
    247   }
    248 
    249   virtual void OnWillRenderTo() const OVERRIDE {
    250     texture_ref_->texture()->OnWillModifyPixels();
    251   }
    252 
    253   virtual void OnDidRenderTo() const OVERRIDE {
    254     texture_ref_->texture()->OnDidModifyPixels();
    255   }
    256 
    257  protected:
    258   virtual ~TextureAttachment() {}
    259 
    260  private:
    261   scoped_refptr<TextureRef> texture_ref_;
    262   GLenum target_;
    263   GLint level_;
    264   GLsizei samples_;
    265 
    266   DISALLOW_COPY_AND_ASSIGN(TextureAttachment);
    267 };
    268 
    269 FramebufferManager::TextureDetachObserver::TextureDetachObserver() {}
    270 
    271 FramebufferManager::TextureDetachObserver::~TextureDetachObserver() {}
    272 
    273 FramebufferManager::FramebufferManager(
    274     uint32 max_draw_buffers, uint32 max_color_attachments)
    275     : framebuffer_state_change_count_(1),
    276       framebuffer_count_(0),
    277       have_context_(true),
    278       max_draw_buffers_(max_draw_buffers),
    279       max_color_attachments_(max_color_attachments) {
    280   DCHECK_GT(max_draw_buffers_, 0u);
    281   DCHECK_GT(max_color_attachments_, 0u);
    282 }
    283 
    284 FramebufferManager::~FramebufferManager() {
    285   DCHECK(framebuffers_.empty());
    286   // If this triggers, that means something is keeping a reference to a
    287   // Framebuffer belonging to this.
    288   CHECK_EQ(framebuffer_count_, 0u);
    289 }
    290 
    291 void Framebuffer::MarkAsDeleted() {
    292   deleted_ = true;
    293   while (!attachments_.empty()) {
    294     Attachment* attachment = attachments_.begin()->second.get();
    295     attachment->DetachFromFramebuffer(this);
    296     attachments_.erase(attachments_.begin());
    297   }
    298 }
    299 
    300 void FramebufferManager::Destroy(bool have_context) {
    301   have_context_ = have_context;
    302   framebuffers_.clear();
    303 }
    304 
    305 void FramebufferManager::StartTracking(
    306     Framebuffer* /* framebuffer */) {
    307   ++framebuffer_count_;
    308 }
    309 
    310 void FramebufferManager::StopTracking(
    311     Framebuffer* /* framebuffer */) {
    312   --framebuffer_count_;
    313 }
    314 
    315 void FramebufferManager::CreateFramebuffer(
    316     GLuint client_id, GLuint service_id) {
    317   std::pair<FramebufferMap::iterator, bool> result =
    318       framebuffers_.insert(
    319           std::make_pair(
    320               client_id,
    321               scoped_refptr<Framebuffer>(
    322                   new Framebuffer(this, service_id))));
    323   DCHECK(result.second);
    324 }
    325 
    326 Framebuffer::Framebuffer(
    327     FramebufferManager* manager, GLuint service_id)
    328     : manager_(manager),
    329       deleted_(false),
    330       service_id_(service_id),
    331       has_been_bound_(false),
    332       framebuffer_complete_state_count_id_(0) {
    333   manager->StartTracking(this);
    334   DCHECK_GT(manager->max_draw_buffers_, 0u);
    335   draw_buffers_.reset(new GLenum[manager->max_draw_buffers_]);
    336   draw_buffers_[0] = GL_COLOR_ATTACHMENT0;
    337   for (uint32 i = 1; i < manager->max_draw_buffers_; ++i)
    338     draw_buffers_[i] = GL_NONE;
    339 }
    340 
    341 Framebuffer::~Framebuffer() {
    342   if (manager_) {
    343     if (manager_->have_context_) {
    344       GLuint id = service_id();
    345       glDeleteFramebuffersEXT(1, &id);
    346     }
    347     manager_->StopTracking(this);
    348     manager_ = NULL;
    349   }
    350 }
    351 
    352 bool Framebuffer::HasUnclearedAttachment(
    353     GLenum attachment) const {
    354   AttachmentMap::const_iterator it =
    355       attachments_.find(attachment);
    356   if (it != attachments_.end()) {
    357     const Attachment* attachment = it->second.get();
    358     return !attachment->cleared();
    359   }
    360   return false;
    361 }
    362 
    363 void Framebuffer::MarkAttachmentAsCleared(
    364       RenderbufferManager* renderbuffer_manager,
    365       TextureManager* texture_manager,
    366       GLenum attachment,
    367       bool cleared) {
    368   AttachmentMap::iterator it = attachments_.find(attachment);
    369   if (it != attachments_.end()) {
    370     Attachment* a = it->second.get();
    371     if (a->cleared() != cleared) {
    372       a->SetCleared(renderbuffer_manager,
    373                     texture_manager,
    374                     cleared);
    375     }
    376   }
    377 }
    378 
    379 void Framebuffer::MarkAttachmentsAsCleared(
    380       RenderbufferManager* renderbuffer_manager,
    381       TextureManager* texture_manager,
    382       bool cleared) {
    383   for (AttachmentMap::iterator it = attachments_.begin();
    384        it != attachments_.end(); ++it) {
    385     Attachment* attachment = it->second.get();
    386     if (attachment->cleared() != cleared) {
    387       attachment->SetCleared(renderbuffer_manager, texture_manager, cleared);
    388     }
    389   }
    390 }
    391 
    392 bool Framebuffer::HasDepthAttachment() const {
    393   return attachments_.find(GL_DEPTH_STENCIL_ATTACHMENT) != attachments_.end() ||
    394          attachments_.find(GL_DEPTH_ATTACHMENT) != attachments_.end();
    395 }
    396 
    397 bool Framebuffer::HasStencilAttachment() const {
    398   return attachments_.find(GL_DEPTH_STENCIL_ATTACHMENT) != attachments_.end() ||
    399          attachments_.find(GL_STENCIL_ATTACHMENT) != attachments_.end();
    400 }
    401 
    402 GLenum Framebuffer::GetColorAttachmentFormat() const {
    403   AttachmentMap::const_iterator it = attachments_.find(GL_COLOR_ATTACHMENT0);
    404   if (it == attachments_.end()) {
    405     return 0;
    406   }
    407   const Attachment* attachment = it->second.get();
    408   return attachment->internal_format();
    409 }
    410 
    411 GLenum Framebuffer::GetColorAttachmentTextureType() const {
    412   AttachmentMap::const_iterator it = attachments_.find(GL_COLOR_ATTACHMENT0);
    413   if (it == attachments_.end()) {
    414     return 0;
    415   }
    416   const Attachment* attachment = it->second.get();
    417   return attachment->texture_type();
    418 }
    419 
    420 GLenum Framebuffer::IsPossiblyComplete() const {
    421   if (attachments_.empty()) {
    422     return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
    423   }
    424 
    425   GLsizei width = -1;
    426   GLsizei height = -1;
    427   for (AttachmentMap::const_iterator it = attachments_.begin();
    428        it != attachments_.end(); ++it) {
    429     GLenum attachment_type = it->first;
    430     Attachment* attachment = it->second.get();
    431     if (!attachment->ValidForAttachmentType(attachment_type,
    432                                             manager_->max_color_attachments_)) {
    433       return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    434     }
    435     if (width < 0) {
    436       width = attachment->width();
    437       height = attachment->height();
    438       if (width == 0 || height == 0) {
    439         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    440       }
    441     } else {
    442       if (attachment->width() != width || attachment->height() != height) {
    443         return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
    444       }
    445     }
    446 
    447     if (!attachment->CanRenderTo()) {
    448       return GL_FRAMEBUFFER_UNSUPPORTED;
    449     }
    450   }
    451 
    452   // This does not mean the framebuffer is actually complete. It just means our
    453   // checks passed.
    454   return GL_FRAMEBUFFER_COMPLETE;
    455 }
    456 
    457 GLenum Framebuffer::GetStatus(
    458     TextureManager* texture_manager, GLenum target) const {
    459   // Check if we have this combo already.
    460   std::string signature;
    461   if (allow_framebuffer_combo_complete_map_) {
    462     signature = base::StringPrintf("|FBO|target=%04x", target);
    463     for (AttachmentMap::const_iterator it = attachments_.begin();
    464          it != attachments_.end(); ++it) {
    465       Attachment* attachment = it->second.get();
    466       signature +=
    467           base::StringPrintf("|Attachment|attachmentpoint=%04x", it->first);
    468       attachment->AddToSignature(texture_manager, &signature);
    469     }
    470 
    471     if (!framebuffer_combo_complete_map_) {
    472       framebuffer_combo_complete_map_ = new FramebufferComboCompleteMap();
    473     }
    474 
    475     FramebufferComboCompleteMap::const_iterator it =
    476         framebuffer_combo_complete_map_->find(signature);
    477     if (it != framebuffer_combo_complete_map_->end()) {
    478       return GL_FRAMEBUFFER_COMPLETE;
    479     }
    480   }
    481 
    482   GLenum result = glCheckFramebufferStatusEXT(target);
    483 
    484   // Insert the new result into the combo map.
    485   if (allow_framebuffer_combo_complete_map_ &&
    486       result == GL_FRAMEBUFFER_COMPLETE) {
    487     framebuffer_combo_complete_map_->insert(std::make_pair(signature, true));
    488   }
    489 
    490   return result;
    491 }
    492 
    493 bool Framebuffer::IsCleared() const {
    494   // are all the attachments cleaared?
    495   for (AttachmentMap::const_iterator it = attachments_.begin();
    496        it != attachments_.end(); ++it) {
    497     Attachment* attachment = it->second.get();
    498     if (!attachment->cleared()) {
    499       return false;
    500     }
    501   }
    502   return true;
    503 }
    504 
    505 GLenum Framebuffer::GetDrawBuffer(GLenum draw_buffer) const {
    506   GLsizei index = static_cast<GLsizei>(
    507       draw_buffer - GL_DRAW_BUFFER0_ARB);
    508   CHECK(index >= 0 &&
    509         index < static_cast<GLsizei>(manager_->max_draw_buffers_));
    510   return draw_buffers_[index];
    511 }
    512 
    513 void Framebuffer::SetDrawBuffers(GLsizei n, const GLenum* bufs) {
    514   DCHECK(n <= static_cast<GLsizei>(manager_->max_draw_buffers_));
    515   for (GLsizei i = 0; i < n; ++i)
    516     draw_buffers_[i] = bufs[i];
    517 }
    518 
    519 bool Framebuffer::HasAlphaMRT() const {
    520   for (uint32 i = 0; i < manager_->max_draw_buffers_; ++i) {
    521     if (draw_buffers_[i] != GL_NONE) {
    522       const Attachment* attachment = GetAttachment(draw_buffers_[i]);
    523       if (!attachment)
    524         continue;
    525       if ((GLES2Util::GetChannelsForFormat(
    526                attachment->internal_format()) & 0x0008) != 0)
    527         return true;
    528     }
    529   }
    530   return false;
    531 }
    532 
    533 void Framebuffer::UnbindRenderbuffer(
    534     GLenum target, Renderbuffer* renderbuffer) {
    535   bool done;
    536   do {
    537     done = true;
    538     for (AttachmentMap::const_iterator it = attachments_.begin();
    539          it != attachments_.end(); ++it) {
    540       Attachment* attachment = it->second.get();
    541       if (attachment->IsRenderbuffer(renderbuffer)) {
    542         // TODO(gman): manually detach renderbuffer.
    543         // glFramebufferRenderbufferEXT(target, it->first, GL_RENDERBUFFER, 0);
    544         AttachRenderbuffer(it->first, NULL);
    545         done = false;
    546         break;
    547       }
    548     }
    549   } while (!done);
    550 }
    551 
    552 void Framebuffer::UnbindTexture(
    553     GLenum target, TextureRef* texture_ref) {
    554   bool done;
    555   do {
    556     done = true;
    557     for (AttachmentMap::const_iterator it = attachments_.begin();
    558          it != attachments_.end(); ++it) {
    559       Attachment* attachment = it->second.get();
    560       if (attachment->IsTexture(texture_ref)) {
    561         // TODO(gman): manually detach texture.
    562         // glFramebufferTexture2DEXT(target, it->first, GL_TEXTURE_2D, 0, 0);
    563         AttachTexture(it->first, NULL, GL_TEXTURE_2D, 0, 0);
    564         done = false;
    565         break;
    566       }
    567     }
    568   } while (!done);
    569 }
    570 
    571 Framebuffer* FramebufferManager::GetFramebuffer(
    572     GLuint client_id) {
    573   FramebufferMap::iterator it = framebuffers_.find(client_id);
    574   return it != framebuffers_.end() ? it->second.get() : NULL;
    575 }
    576 
    577 void FramebufferManager::RemoveFramebuffer(GLuint client_id) {
    578   FramebufferMap::iterator it = framebuffers_.find(client_id);
    579   if (it != framebuffers_.end()) {
    580     it->second->MarkAsDeleted();
    581     framebuffers_.erase(it);
    582   }
    583 }
    584 
    585 void Framebuffer::AttachRenderbuffer(
    586     GLenum attachment, Renderbuffer* renderbuffer) {
    587   const Attachment* a = GetAttachment(attachment);
    588   if (a)
    589     a->DetachFromFramebuffer(this);
    590   if (renderbuffer) {
    591     attachments_[attachment] = scoped_refptr<Attachment>(
    592         new RenderbufferAttachment(renderbuffer));
    593   } else {
    594     attachments_.erase(attachment);
    595   }
    596   framebuffer_complete_state_count_id_ = 0;
    597 }
    598 
    599 void Framebuffer::AttachTexture(
    600     GLenum attachment, TextureRef* texture_ref, GLenum target,
    601     GLint level, GLsizei samples) {
    602   const Attachment* a = GetAttachment(attachment);
    603   if (a)
    604     a->DetachFromFramebuffer(this);
    605   if (texture_ref) {
    606     attachments_[attachment] = scoped_refptr<Attachment>(
    607         new TextureAttachment(texture_ref, target, level, samples));
    608     texture_ref->texture()->AttachToFramebuffer();
    609   } else {
    610     attachments_.erase(attachment);
    611   }
    612   framebuffer_complete_state_count_id_ = 0;
    613 }
    614 
    615 const Framebuffer::Attachment*
    616     Framebuffer::GetAttachment(
    617         GLenum attachment) const {
    618   AttachmentMap::const_iterator it = attachments_.find(attachment);
    619   if (it != attachments_.end()) {
    620     return it->second.get();
    621   }
    622   return NULL;
    623 }
    624 
    625 void Framebuffer::OnTextureRefDetached(TextureRef* texture) {
    626   manager_->OnTextureRefDetached(texture);
    627 }
    628 
    629 void Framebuffer::OnWillRenderTo() const {
    630   for (AttachmentMap::const_iterator it = attachments_.begin();
    631        it != attachments_.end(); ++it) {
    632     it->second->OnWillRenderTo();
    633   }
    634 }
    635 
    636 void Framebuffer::OnDidRenderTo() const {
    637   for (AttachmentMap::const_iterator it = attachments_.begin();
    638        it != attachments_.end(); ++it) {
    639     it->second->OnDidRenderTo();
    640   }
    641 }
    642 
    643 bool FramebufferManager::GetClientId(
    644     GLuint service_id, GLuint* client_id) const {
    645   // This doesn't need to be fast. It's only used during slow queries.
    646   for (FramebufferMap::const_iterator it = framebuffers_.begin();
    647        it != framebuffers_.end(); ++it) {
    648     if (it->second->service_id() == service_id) {
    649       *client_id = it->first;
    650       return true;
    651     }
    652   }
    653   return false;
    654 }
    655 
    656 void FramebufferManager::MarkAttachmentsAsCleared(
    657     Framebuffer* framebuffer,
    658     RenderbufferManager* renderbuffer_manager,
    659     TextureManager* texture_manager) {
    660   DCHECK(framebuffer);
    661   framebuffer->MarkAttachmentsAsCleared(renderbuffer_manager,
    662                                         texture_manager,
    663                                         true);
    664   MarkAsComplete(framebuffer);
    665 }
    666 
    667 void FramebufferManager::MarkAsComplete(
    668     Framebuffer* framebuffer) {
    669   DCHECK(framebuffer);
    670   framebuffer->MarkAsComplete(framebuffer_state_change_count_);
    671 }
    672 
    673 bool FramebufferManager::IsComplete(
    674     Framebuffer* framebuffer) {
    675   DCHECK(framebuffer);
    676   return framebuffer->framebuffer_complete_state_count_id() ==
    677       framebuffer_state_change_count_;
    678 }
    679 
    680 void FramebufferManager::OnTextureRefDetached(TextureRef* texture) {
    681   for (TextureDetachObserverVector::iterator it =
    682            texture_detach_observers_.begin();
    683        it != texture_detach_observers_.end();
    684        ++it) {
    685     TextureDetachObserver* observer = *it;
    686     observer->OnTextureRefDetachedFromFramebuffer(texture);
    687   }
    688 }
    689 
    690 }  // namespace gles2
    691 }  // namespace gpu
    692 
    693 
    694