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