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
13namespace gpu {
14namespace gles2 {
15
16DecoderFramebufferState::DecoderFramebufferState()
17    : clear_state_dirty(false),
18      bound_read_framebuffer(NULL),
19      bound_draw_framebuffer(NULL) {
20}
21
22DecoderFramebufferState::~DecoderFramebufferState() {
23}
24
25Framebuffer::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)
32bool Framebuffer::allow_framebuffer_combo_complete_map_ = false;
33#else
34bool Framebuffer::allow_framebuffer_combo_complete_map_ = true;
35#endif
36
37void Framebuffer::ClearFramebufferCompleteComboMap() {
38  if (framebuffer_combo_complete_map_) {
39    framebuffer_combo_complete_map_->clear();
40  }
41}
42
43class 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
134class 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
269FramebufferManager::TextureDetachObserver::TextureDetachObserver() {}
270
271FramebufferManager::TextureDetachObserver::~TextureDetachObserver() {}
272
273FramebufferManager::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
284FramebufferManager::~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
291void 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
300void FramebufferManager::Destroy(bool have_context) {
301  have_context_ = have_context;
302  framebuffers_.clear();
303}
304
305void FramebufferManager::StartTracking(
306    Framebuffer* /* framebuffer */) {
307  ++framebuffer_count_;
308}
309
310void FramebufferManager::StopTracking(
311    Framebuffer* /* framebuffer */) {
312  --framebuffer_count_;
313}
314
315void 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
326Framebuffer::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
341Framebuffer::~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
352bool 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
363bool 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
376void 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
402void Framebuffer::PrepareDrawBuffersForClear() const {
403  bool recover = false;
404  ChangeDrawBuffersHelper(recover);
405}
406
407void Framebuffer::RestoreDrawBuffersAfterClear() const {
408  bool recover = true;
409  ChangeDrawBuffersHelper(recover);
410}
411
412void 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
428void 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
441bool Framebuffer::HasDepthAttachment() const {
442  return attachments_.find(GL_DEPTH_STENCIL_ATTACHMENT) != attachments_.end() ||
443         attachments_.find(GL_DEPTH_ATTACHMENT) != attachments_.end();
444}
445
446bool Framebuffer::HasStencilAttachment() const {
447  return attachments_.find(GL_DEPTH_STENCIL_ATTACHMENT) != attachments_.end() ||
448         attachments_.find(GL_STENCIL_ATTACHMENT) != attachments_.end();
449}
450
451GLenum 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
460GLenum 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
469GLenum 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
506GLenum 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
542bool 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
554GLenum 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
562void 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
570bool 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
584void 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
603void 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
622Framebuffer* 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
628void 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
636void 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
650void 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
666const 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
676void Framebuffer::OnTextureRefDetached(TextureRef* texture) {
677  manager_->OnTextureRefDetached(texture);
678}
679
680void Framebuffer::OnWillRenderTo() const {
681  for (AttachmentMap::const_iterator it = attachments_.begin();
682       it != attachments_.end(); ++it) {
683    it->second->OnWillRenderTo();
684  }
685}
686
687void Framebuffer::OnDidRenderTo() const {
688  for (AttachmentMap::const_iterator it = attachments_.begin();
689       it != attachments_.end(); ++it) {
690    it->second->OnDidRenderTo();
691  }
692}
693
694bool 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
707void 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
718void FramebufferManager::MarkAsComplete(
719    Framebuffer* framebuffer) {
720  DCHECK(framebuffer);
721  framebuffer->MarkAsComplete(framebuffer_state_change_count_);
722}
723
724bool FramebufferManager::IsComplete(
725    Framebuffer* framebuffer) {
726  DCHECK(framebuffer);
727  return framebuffer->framebuffer_complete_state_count_id() ==
728      framebuffer_state_change_count_;
729}
730
731void 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