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 bool Framebuffer::HasUnclearedColorAttachments() const {
    364   for (AttachmentMap::const_iterator it = attachments_.begin();
    365        it != attachments_.end(); ++it) {
    366     if (it->first >= GL_COLOR_ATTACHMENT0 &&
    367         it->first < GL_COLOR_ATTACHMENT0 + manager_->max_draw_buffers_) {
    368       const Attachment* attachment = it->second.get();
    369       if (!attachment->cleared())
    370         return true;
    371     }
    372   }
    373   return false;
    374 }
    375 
    376 void Framebuffer::ChangeDrawBuffersHelper(bool recover) const {
    377   scoped_ptr<GLenum[]> buffers(new GLenum[manager_->max_draw_buffers_]);
    378   for (uint32 i = 0; i < manager_->max_draw_buffers_; ++i)
    379     buffers[i] = GL_NONE;
    380   for (AttachmentMap::const_iterator it = attachments_.begin();
    381        it != attachments_.end(); ++it) {
    382     if (it->first >= GL_COLOR_ATTACHMENT0 &&
    383         it->first < GL_COLOR_ATTACHMENT0 + manager_->max_draw_buffers_) {
    384       buffers[it->first - GL_COLOR_ATTACHMENT0] = it->first;
    385     }
    386   }
    387   bool different = false;
    388   for (uint32 i = 0; i < manager_->max_draw_buffers_; ++i) {
    389     if (buffers[i] != draw_buffers_[i]) {
    390       different = true;
    391       break;
    392     }
    393   }
    394   if (different) {
    395     if (recover)
    396       glDrawBuffersARB(manager_->max_draw_buffers_, draw_buffers_.get());
    397     else
    398       glDrawBuffersARB(manager_->max_draw_buffers_, buffers.get());
    399   }
    400 }
    401 
    402 void Framebuffer::PrepareDrawBuffersForClear() const {
    403   bool recover = false;
    404   ChangeDrawBuffersHelper(recover);
    405 }
    406 
    407 void Framebuffer::RestoreDrawBuffersAfterClear() const {
    408   bool recover = true;
    409   ChangeDrawBuffersHelper(recover);
    410 }
    411 
    412 void Framebuffer::MarkAttachmentAsCleared(
    413       RenderbufferManager* renderbuffer_manager,
    414       TextureManager* texture_manager,
    415       GLenum attachment,
    416       bool cleared) {
    417   AttachmentMap::iterator it = attachments_.find(attachment);
    418   if (it != attachments_.end()) {
    419     Attachment* a = it->second.get();
    420     if (a->cleared() != cleared) {
    421       a->SetCleared(renderbuffer_manager,
    422                     texture_manager,
    423                     cleared);
    424     }
    425   }
    426 }
    427 
    428 void Framebuffer::MarkAttachmentsAsCleared(
    429       RenderbufferManager* renderbuffer_manager,
    430       TextureManager* texture_manager,
    431       bool cleared) {
    432   for (AttachmentMap::iterator it = attachments_.begin();
    433        it != attachments_.end(); ++it) {
    434     Attachment* attachment = it->second.get();
    435     if (attachment->cleared() != cleared) {
    436       attachment->SetCleared(renderbuffer_manager, texture_manager, cleared);
    437     }
    438   }
    439 }
    440 
    441 bool Framebuffer::HasDepthAttachment() const {
    442   return attachments_.find(GL_DEPTH_STENCIL_ATTACHMENT) != attachments_.end() ||
    443          attachments_.find(GL_DEPTH_ATTACHMENT) != attachments_.end();
    444 }
    445 
    446 bool Framebuffer::HasStencilAttachment() const {
    447   return attachments_.find(GL_DEPTH_STENCIL_ATTACHMENT) != attachments_.end() ||
    448          attachments_.find(GL_STENCIL_ATTACHMENT) != attachments_.end();
    449 }
    450 
    451 GLenum Framebuffer::GetColorAttachmentFormat() const {
    452   AttachmentMap::const_iterator it = attachments_.find(GL_COLOR_ATTACHMENT0);
    453   if (it == attachments_.end()) {
    454     return 0;
    455   }
    456   const Attachment* attachment = it->second.get();
    457   return attachment->internal_format();
    458 }
    459 
    460 GLenum Framebuffer::GetColorAttachmentTextureType() const {
    461   AttachmentMap::const_iterator it = attachments_.find(GL_COLOR_ATTACHMENT0);
    462   if (it == attachments_.end()) {
    463     return 0;
    464   }
    465   const Attachment* attachment = it->second.get();
    466   return attachment->texture_type();
    467 }
    468 
    469 GLenum Framebuffer::IsPossiblyComplete() const {
    470   if (attachments_.empty()) {
    471     return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
    472   }
    473 
    474   GLsizei width = -1;
    475   GLsizei height = -1;
    476   for (AttachmentMap::const_iterator it = attachments_.begin();
    477        it != attachments_.end(); ++it) {
    478     GLenum attachment_type = it->first;
    479     Attachment* attachment = it->second.get();
    480     if (!attachment->ValidForAttachmentType(attachment_type,
    481                                             manager_->max_color_attachments_)) {
    482       return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    483     }
    484     if (width < 0) {
    485       width = attachment->width();
    486       height = attachment->height();
    487       if (width == 0 || height == 0) {
    488         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    489       }
    490     } else {
    491       if (attachment->width() != width || attachment->height() != height) {
    492         return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
    493       }
    494     }
    495 
    496     if (!attachment->CanRenderTo()) {
    497       return GL_FRAMEBUFFER_UNSUPPORTED;
    498     }
    499   }
    500 
    501   // This does not mean the framebuffer is actually complete. It just means our
    502   // checks passed.
    503   return GL_FRAMEBUFFER_COMPLETE;
    504 }
    505 
    506 GLenum Framebuffer::GetStatus(
    507     TextureManager* texture_manager, GLenum target) const {
    508   // Check if we have this combo already.
    509   std::string signature;
    510   if (allow_framebuffer_combo_complete_map_) {
    511     signature = base::StringPrintf("|FBO|target=%04x", target);
    512     for (AttachmentMap::const_iterator it = attachments_.begin();
    513          it != attachments_.end(); ++it) {
    514       Attachment* attachment = it->second.get();
    515       signature +=
    516           base::StringPrintf("|Attachment|attachmentpoint=%04x", it->first);
    517       attachment->AddToSignature(texture_manager, &signature);
    518     }
    519 
    520     if (!framebuffer_combo_complete_map_) {
    521       framebuffer_combo_complete_map_ = new FramebufferComboCompleteMap();
    522     }
    523 
    524     FramebufferComboCompleteMap::const_iterator it =
    525         framebuffer_combo_complete_map_->find(signature);
    526     if (it != framebuffer_combo_complete_map_->end()) {
    527       return GL_FRAMEBUFFER_COMPLETE;
    528     }
    529   }
    530 
    531   GLenum result = glCheckFramebufferStatusEXT(target);
    532 
    533   // Insert the new result into the combo map.
    534   if (allow_framebuffer_combo_complete_map_ &&
    535       result == GL_FRAMEBUFFER_COMPLETE) {
    536     framebuffer_combo_complete_map_->insert(std::make_pair(signature, true));
    537   }
    538 
    539   return result;
    540 }
    541 
    542 bool Framebuffer::IsCleared() const {
    543   // are all the attachments cleaared?
    544   for (AttachmentMap::const_iterator it = attachments_.begin();
    545        it != attachments_.end(); ++it) {
    546     Attachment* attachment = it->second.get();
    547     if (!attachment->cleared()) {
    548       return false;
    549     }
    550   }
    551   return true;
    552 }
    553 
    554 GLenum Framebuffer::GetDrawBuffer(GLenum draw_buffer) const {
    555   GLsizei index = static_cast<GLsizei>(
    556       draw_buffer - GL_DRAW_BUFFER0_ARB);
    557   CHECK(index >= 0 &&
    558         index < static_cast<GLsizei>(manager_->max_draw_buffers_));
    559   return draw_buffers_[index];
    560 }
    561 
    562 void Framebuffer::SetDrawBuffers(GLsizei n, const GLenum* bufs) {
    563   DCHECK(n <= static_cast<GLsizei>(manager_->max_draw_buffers_));
    564   for (GLsizei i = 0; i < n; ++i)
    565     draw_buffers_[i] = bufs[i];
    566 }
    567 
    568 
    569 
    570 bool Framebuffer::HasAlphaMRT() const {
    571   for (uint32 i = 0; i < manager_->max_draw_buffers_; ++i) {
    572     if (draw_buffers_[i] != GL_NONE) {
    573       const Attachment* attachment = GetAttachment(draw_buffers_[i]);
    574       if (!attachment)
    575         continue;
    576       if ((GLES2Util::GetChannelsForFormat(
    577                attachment->internal_format()) & 0x0008) != 0)
    578         return true;
    579     }
    580   }
    581   return false;
    582 }
    583 
    584 void Framebuffer::UnbindRenderbuffer(
    585     GLenum target, Renderbuffer* renderbuffer) {
    586   bool done;
    587   do {
    588     done = true;
    589     for (AttachmentMap::const_iterator it = attachments_.begin();
    590          it != attachments_.end(); ++it) {
    591       Attachment* attachment = it->second.get();
    592       if (attachment->IsRenderbuffer(renderbuffer)) {
    593         // TODO(gman): manually detach renderbuffer.
    594         // glFramebufferRenderbufferEXT(target, it->first, GL_RENDERBUFFER, 0);
    595         AttachRenderbuffer(it->first, NULL);
    596         done = false;
    597         break;
    598       }
    599     }
    600   } while (!done);
    601 }
    602 
    603 void Framebuffer::UnbindTexture(
    604     GLenum target, TextureRef* texture_ref) {
    605   bool done;
    606   do {
    607     done = true;
    608     for (AttachmentMap::const_iterator it = attachments_.begin();
    609          it != attachments_.end(); ++it) {
    610       Attachment* attachment = it->second.get();
    611       if (attachment->IsTexture(texture_ref)) {
    612         // TODO(gman): manually detach texture.
    613         // glFramebufferTexture2DEXT(target, it->first, GL_TEXTURE_2D, 0, 0);
    614         AttachTexture(it->first, NULL, GL_TEXTURE_2D, 0, 0);
    615         done = false;
    616         break;
    617       }
    618     }
    619   } while (!done);
    620 }
    621 
    622 Framebuffer* FramebufferManager::GetFramebuffer(
    623     GLuint client_id) {
    624   FramebufferMap::iterator it = framebuffers_.find(client_id);
    625   return it != framebuffers_.end() ? it->second.get() : NULL;
    626 }
    627 
    628 void FramebufferManager::RemoveFramebuffer(GLuint client_id) {
    629   FramebufferMap::iterator it = framebuffers_.find(client_id);
    630   if (it != framebuffers_.end()) {
    631     it->second->MarkAsDeleted();
    632     framebuffers_.erase(it);
    633   }
    634 }
    635 
    636 void Framebuffer::AttachRenderbuffer(
    637     GLenum attachment, Renderbuffer* renderbuffer) {
    638   const Attachment* a = GetAttachment(attachment);
    639   if (a)
    640     a->DetachFromFramebuffer(this);
    641   if (renderbuffer) {
    642     attachments_[attachment] = scoped_refptr<Attachment>(
    643         new RenderbufferAttachment(renderbuffer));
    644   } else {
    645     attachments_.erase(attachment);
    646   }
    647   framebuffer_complete_state_count_id_ = 0;
    648 }
    649 
    650 void Framebuffer::AttachTexture(
    651     GLenum attachment, TextureRef* texture_ref, GLenum target,
    652     GLint level, GLsizei samples) {
    653   const Attachment* a = GetAttachment(attachment);
    654   if (a)
    655     a->DetachFromFramebuffer(this);
    656   if (texture_ref) {
    657     attachments_[attachment] = scoped_refptr<Attachment>(
    658         new TextureAttachment(texture_ref, target, level, samples));
    659     texture_ref->texture()->AttachToFramebuffer();
    660   } else {
    661     attachments_.erase(attachment);
    662   }
    663   framebuffer_complete_state_count_id_ = 0;
    664 }
    665 
    666 const Framebuffer::Attachment*
    667     Framebuffer::GetAttachment(
    668         GLenum attachment) const {
    669   AttachmentMap::const_iterator it = attachments_.find(attachment);
    670   if (it != attachments_.end()) {
    671     return it->second.get();
    672   }
    673   return NULL;
    674 }
    675 
    676 void Framebuffer::OnTextureRefDetached(TextureRef* texture) {
    677   manager_->OnTextureRefDetached(texture);
    678 }
    679 
    680 void Framebuffer::OnWillRenderTo() const {
    681   for (AttachmentMap::const_iterator it = attachments_.begin();
    682        it != attachments_.end(); ++it) {
    683     it->second->OnWillRenderTo();
    684   }
    685 }
    686 
    687 void Framebuffer::OnDidRenderTo() const {
    688   for (AttachmentMap::const_iterator it = attachments_.begin();
    689        it != attachments_.end(); ++it) {
    690     it->second->OnDidRenderTo();
    691   }
    692 }
    693 
    694 bool FramebufferManager::GetClientId(
    695     GLuint service_id, GLuint* client_id) const {
    696   // This doesn't need to be fast. It's only used during slow queries.
    697   for (FramebufferMap::const_iterator it = framebuffers_.begin();
    698        it != framebuffers_.end(); ++it) {
    699     if (it->second->service_id() == service_id) {
    700       *client_id = it->first;
    701       return true;
    702     }
    703   }
    704   return false;
    705 }
    706 
    707 void FramebufferManager::MarkAttachmentsAsCleared(
    708     Framebuffer* framebuffer,
    709     RenderbufferManager* renderbuffer_manager,
    710     TextureManager* texture_manager) {
    711   DCHECK(framebuffer);
    712   framebuffer->MarkAttachmentsAsCleared(renderbuffer_manager,
    713                                         texture_manager,
    714                                         true);
    715   MarkAsComplete(framebuffer);
    716 }
    717 
    718 void FramebufferManager::MarkAsComplete(
    719     Framebuffer* framebuffer) {
    720   DCHECK(framebuffer);
    721   framebuffer->MarkAsComplete(framebuffer_state_change_count_);
    722 }
    723 
    724 bool FramebufferManager::IsComplete(
    725     Framebuffer* framebuffer) {
    726   DCHECK(framebuffer);
    727   return framebuffer->framebuffer_complete_state_count_id() ==
    728       framebuffer_state_change_count_;
    729 }
    730 
    731 void FramebufferManager::OnTextureRefDetached(TextureRef* texture) {
    732   for (TextureDetachObserverVector::iterator it =
    733            texture_detach_observers_.begin();
    734        it != texture_detach_observers_.end();
    735        ++it) {
    736     TextureDetachObserver* observer = *it;
    737     observer->OnTextureRefDetachedFromFramebuffer(texture);
    738   }
    739 }
    740 
    741 }  // namespace gles2
    742 }  // namespace gpu
    743 
    744 
    745