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.
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"
16 DecoderFramebufferState::DecoderFramebufferState()
17 : clear_state_dirty(false),
18 bound_read_framebuffer(NULL
),
19 bound_draw_framebuffer(NULL
) {
22 DecoderFramebufferState::~DecoderFramebufferState() {
25 Framebuffer::FramebufferComboCompleteMap
*
26 Framebuffer::framebuffer_combo_complete_map_
;
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;
34 bool Framebuffer::allow_framebuffer_combo_complete_map_
= true;
37 void Framebuffer::ClearFramebufferCompleteComboMap() {
38 if (framebuffer_combo_complete_map_
) {
39 framebuffer_combo_complete_map_
->clear();
43 class RenderbufferAttachment
44 : public Framebuffer::Attachment
{
46 explicit RenderbufferAttachment(
47 Renderbuffer
* renderbuffer
)
48 : renderbuffer_(renderbuffer
) {
51 GLsizei
width() const override
{ return renderbuffer_
->width(); }
53 GLsizei
height() const override
{ return renderbuffer_
->height(); }
55 GLenum
internal_format() const override
{
56 return renderbuffer_
->internal_format();
59 GLenum
texture_type() const override
{ return 0; }
61 GLsizei
samples() const override
{ return renderbuffer_
->samples(); }
63 GLuint
object_name() const override
{ return renderbuffer_
->client_id(); }
65 bool cleared() const override
{ return renderbuffer_
->cleared(); }
67 void SetCleared(RenderbufferManager
* renderbuffer_manager
,
68 TextureManager
* /* texture_manager */,
69 bool cleared
) override
{
70 renderbuffer_manager
->SetCleared(renderbuffer_
.get(), cleared
);
73 bool IsTexture(TextureRef
* /* texture */) const override
{ return false; }
75 bool IsRenderbuffer(Renderbuffer
* renderbuffer
) const override
{
76 return renderbuffer_
.get() == renderbuffer
;
79 bool CanRenderTo() const override
{ return true; }
81 void DetachFromFramebuffer(Framebuffer
* framebuffer
) const override
{
82 // Nothing to do for renderbuffers.
85 bool ValidForAttachmentType(GLenum attachment_type
,
86 uint32 max_color_attachments
) override
{
87 uint32 need
= GLES2Util::GetChannelsNeededForAttachmentType(
88 attachment_type
, max_color_attachments
);
89 uint32 have
= GLES2Util::GetChannelsForFormat(internal_format());
90 return (need
& have
) != 0;
93 Renderbuffer
* renderbuffer() const {
94 return renderbuffer_
.get();
97 size_t GetSignatureSize(TextureManager
* texture_manager
) const override
{
98 return renderbuffer_
->GetSignatureSize();
101 void AddToSignature(TextureManager
* texture_manager
,
102 std::string
* signature
) const override
{
104 renderbuffer_
->AddToSignature(signature
);
107 void OnWillRenderTo() const override
{}
108 void OnDidRenderTo() const override
{}
109 bool FormsFeedbackLoop(TextureRef
* /* texture */,
110 GLint
/*level */) const override
{
115 ~RenderbufferAttachment() override
{}
118 scoped_refptr
<Renderbuffer
> renderbuffer_
;
120 DISALLOW_COPY_AND_ASSIGN(RenderbufferAttachment
);
123 class TextureAttachment
124 : public Framebuffer::Attachment
{
127 TextureRef
* texture_ref
, GLenum target
, GLint level
, GLsizei samples
)
128 : texture_ref_(texture_ref
),
134 GLsizei
width() const override
{
135 GLsizei temp_width
= 0;
136 GLsizei temp_height
= 0;
137 texture_ref_
->texture()->GetLevelSize(
138 target_
, level_
, &temp_width
, &temp_height
, nullptr);
142 GLsizei
height() const override
{
143 GLsizei temp_width
= 0;
144 GLsizei temp_height
= 0;
145 texture_ref_
->texture()->GetLevelSize(
146 target_
, level_
, &temp_width
, &temp_height
, nullptr);
150 GLenum
internal_format() const override
{
151 GLenum temp_type
= 0;
152 GLenum temp_internal_format
= 0;
153 texture_ref_
->texture()->GetLevelType(
154 target_
, level_
, &temp_type
, &temp_internal_format
);
155 return temp_internal_format
;
158 GLenum
texture_type() const override
{
159 GLenum temp_type
= 0;
160 GLenum temp_internal_format
= 0;
161 texture_ref_
->texture()->GetLevelType(
162 target_
, level_
, &temp_type
, &temp_internal_format
);
166 GLsizei
samples() const override
{ return samples_
; }
168 GLuint
object_name() const override
{ return texture_ref_
->client_id(); }
170 bool cleared() const override
{
171 return texture_ref_
->texture()->IsLevelCleared(target_
, level_
);
174 void SetCleared(RenderbufferManager
* /* renderbuffer_manager */,
175 TextureManager
* texture_manager
,
176 bool cleared
) override
{
177 texture_manager
->SetLevelCleared(
178 texture_ref_
.get(), target_
, level_
, cleared
);
181 bool IsTexture(TextureRef
* texture
) const override
{
182 return texture
== texture_ref_
.get();
185 bool IsRenderbuffer(Renderbuffer
* /* renderbuffer */) const override
{
189 TextureRef
* texture() const {
190 return texture_ref_
.get();
193 bool CanRenderTo() const override
{
194 return texture_ref_
->texture()->CanRenderTo();
197 void DetachFromFramebuffer(Framebuffer
* framebuffer
) const override
{
198 texture_ref_
->texture()->DetachFromFramebuffer();
199 framebuffer
->OnTextureRefDetached(texture_ref_
.get());
202 bool ValidForAttachmentType(GLenum attachment_type
,
203 uint32 max_color_attachments
) override
{
205 GLenum internal_format
= 0;
206 if (!texture_ref_
->texture()->GetLevelType(
207 target_
, level_
, &type
, &internal_format
)) {
210 uint32 need
= GLES2Util::GetChannelsNeededForAttachmentType(
211 attachment_type
, max_color_attachments
);
212 uint32 have
= GLES2Util::GetChannelsForFormat(internal_format
);
214 // Workaround for NVIDIA drivers that incorrectly expose these formats as
216 if (internal_format
== GL_LUMINANCE
|| internal_format
== GL_ALPHA
||
217 internal_format
== GL_LUMINANCE_ALPHA
) {
220 return (need
& have
) != 0;
223 size_t GetSignatureSize(TextureManager
* texture_manager
) const override
{
224 return texture_manager
->GetSignatureSize();
227 void AddToSignature(TextureManager
* texture_manager
,
228 std::string
* signature
) const override
{
230 texture_manager
->AddToSignature(
231 texture_ref_
.get(), target_
, level_
, signature
);
234 void OnWillRenderTo() const override
{
235 texture_ref_
->texture()->OnWillModifyPixels();
238 void OnDidRenderTo() const override
{
239 texture_ref_
->texture()->OnDidModifyPixels();
242 bool FormsFeedbackLoop(TextureRef
* texture
, GLint level
) const override
{
243 return texture
== texture_ref_
.get() && level
== level_
;
247 ~TextureAttachment() override
{}
250 scoped_refptr
<TextureRef
> texture_ref_
;
255 DISALLOW_COPY_AND_ASSIGN(TextureAttachment
);
258 FramebufferManager::TextureDetachObserver::TextureDetachObserver() {}
260 FramebufferManager::TextureDetachObserver::~TextureDetachObserver() {}
262 FramebufferManager::FramebufferManager(
263 uint32 max_draw_buffers
, uint32 max_color_attachments
,
264 ContextGroup::ContextType context_type
)
265 : framebuffer_state_change_count_(1),
266 framebuffer_count_(0),
268 max_draw_buffers_(max_draw_buffers
),
269 max_color_attachments_(max_color_attachments
),
270 context_type_(context_type
) {
271 DCHECK_GT(max_draw_buffers_
, 0u);
272 DCHECK_GT(max_color_attachments_
, 0u);
275 FramebufferManager::~FramebufferManager() {
276 DCHECK(framebuffers_
.empty());
277 // If this triggers, that means something is keeping a reference to a
278 // Framebuffer belonging to this.
279 CHECK_EQ(framebuffer_count_
, 0u);
282 void Framebuffer::MarkAsDeleted() {
284 while (!attachments_
.empty()) {
285 Attachment
* attachment
= attachments_
.begin()->second
.get();
286 attachment
->DetachFromFramebuffer(this);
287 attachments_
.erase(attachments_
.begin());
291 void FramebufferManager::Destroy(bool have_context
) {
292 have_context_
= have_context
;
293 framebuffers_
.clear();
296 void FramebufferManager::StartTracking(
297 Framebuffer
* /* framebuffer */) {
298 ++framebuffer_count_
;
301 void FramebufferManager::StopTracking(
302 Framebuffer
* /* framebuffer */) {
303 --framebuffer_count_
;
306 void FramebufferManager::CreateFramebuffer(
307 GLuint client_id
, GLuint service_id
) {
308 std::pair
<FramebufferMap::iterator
, bool> result
=
309 framebuffers_
.insert(
312 scoped_refptr
<Framebuffer
>(
313 new Framebuffer(this, service_id
))));
314 DCHECK(result
.second
);
317 Framebuffer::Framebuffer(
318 FramebufferManager
* manager
, GLuint service_id
)
321 service_id_(service_id
),
322 has_been_bound_(false),
323 framebuffer_complete_state_count_id_(0),
324 read_buffer_(GL_COLOR_ATTACHMENT0
) {
325 manager
->StartTracking(this);
326 DCHECK_GT(manager
->max_draw_buffers_
, 0u);
327 draw_buffers_
.reset(new GLenum
[manager
->max_draw_buffers_
]);
328 draw_buffers_
[0] = GL_COLOR_ATTACHMENT0
;
329 for (uint32 i
= 1; i
< manager
->max_draw_buffers_
; ++i
)
330 draw_buffers_
[i
] = GL_NONE
;
333 Framebuffer::~Framebuffer() {
335 if (manager_
->have_context_
) {
336 GLuint id
= service_id();
337 glDeleteFramebuffersEXT(1, &id
);
339 manager_
->StopTracking(this);
344 bool Framebuffer::HasUnclearedAttachment(
345 GLenum attachment
) const {
346 AttachmentMap::const_iterator it
=
347 attachments_
.find(attachment
);
348 if (it
!= attachments_
.end()) {
349 const Attachment
* attachment
= it
->second
.get();
350 return !attachment
->cleared();
355 bool Framebuffer::HasUnclearedColorAttachments() const {
356 for (AttachmentMap::const_iterator it
= attachments_
.begin();
357 it
!= attachments_
.end(); ++it
) {
358 if (it
->first
>= GL_COLOR_ATTACHMENT0
&&
359 it
->first
< GL_COLOR_ATTACHMENT0
+ manager_
->max_draw_buffers_
) {
360 const Attachment
* attachment
= it
->second
.get();
361 if (!attachment
->cleared())
368 void Framebuffer::ChangeDrawBuffersHelper(bool recover
) const {
369 scoped_ptr
<GLenum
[]> buffers(new GLenum
[manager_
->max_draw_buffers_
]);
370 for (uint32 i
= 0; i
< manager_
->max_draw_buffers_
; ++i
)
371 buffers
[i
] = GL_NONE
;
372 for (AttachmentMap::const_iterator it
= attachments_
.begin();
373 it
!= attachments_
.end(); ++it
) {
374 if (it
->first
>= GL_COLOR_ATTACHMENT0
&&
375 it
->first
< GL_COLOR_ATTACHMENT0
+ manager_
->max_draw_buffers_
) {
376 buffers
[it
->first
- GL_COLOR_ATTACHMENT0
] = it
->first
;
379 bool different
= false;
380 for (uint32 i
= 0; i
< manager_
->max_draw_buffers_
; ++i
) {
381 if (buffers
[i
] != draw_buffers_
[i
]) {
388 glDrawBuffersARB(manager_
->max_draw_buffers_
, draw_buffers_
.get());
390 glDrawBuffersARB(manager_
->max_draw_buffers_
, buffers
.get());
394 void Framebuffer::PrepareDrawBuffersForClear() const {
395 bool recover
= false;
396 ChangeDrawBuffersHelper(recover
);
399 void Framebuffer::RestoreDrawBuffersAfterClear() const {
401 ChangeDrawBuffersHelper(recover
);
404 void Framebuffer::MarkAttachmentAsCleared(
405 RenderbufferManager
* renderbuffer_manager
,
406 TextureManager
* texture_manager
,
409 AttachmentMap::iterator it
= attachments_
.find(attachment
);
410 if (it
!= attachments_
.end()) {
411 Attachment
* a
= it
->second
.get();
412 if (a
->cleared() != cleared
) {
413 a
->SetCleared(renderbuffer_manager
,
420 void Framebuffer::MarkAttachmentsAsCleared(
421 RenderbufferManager
* renderbuffer_manager
,
422 TextureManager
* texture_manager
,
424 for (AttachmentMap::iterator it
= attachments_
.begin();
425 it
!= attachments_
.end(); ++it
) {
426 Attachment
* attachment
= it
->second
.get();
427 if (attachment
->cleared() != cleared
) {
428 attachment
->SetCleared(renderbuffer_manager
, texture_manager
, cleared
);
433 bool Framebuffer::HasDepthAttachment() const {
434 return attachments_
.find(GL_DEPTH_STENCIL_ATTACHMENT
) != attachments_
.end() ||
435 attachments_
.find(GL_DEPTH_ATTACHMENT
) != attachments_
.end();
438 bool Framebuffer::HasStencilAttachment() const {
439 return attachments_
.find(GL_DEPTH_STENCIL_ATTACHMENT
) != attachments_
.end() ||
440 attachments_
.find(GL_STENCIL_ATTACHMENT
) != attachments_
.end();
443 GLenum
Framebuffer::GetReadBufferInternalFormat() const {
444 if (read_buffer_
== GL_NONE
)
446 AttachmentMap::const_iterator it
= attachments_
.find(read_buffer_
);
447 if (it
== attachments_
.end()) {
450 const Attachment
* attachment
= it
->second
.get();
451 return attachment
->internal_format();
454 GLenum
Framebuffer::GetReadBufferTextureType() const {
455 if (read_buffer_
== GL_NONE
)
457 AttachmentMap::const_iterator it
= attachments_
.find(read_buffer_
);
458 if (it
== attachments_
.end()) {
461 const Attachment
* attachment
= it
->second
.get();
462 return attachment
->texture_type();
465 GLenum
Framebuffer::IsPossiblyComplete() const {
466 if (attachments_
.empty()) {
467 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
;
472 for (AttachmentMap::const_iterator it
= attachments_
.begin();
473 it
!= attachments_
.end(); ++it
) {
474 GLenum attachment_type
= it
->first
;
475 Attachment
* attachment
= it
->second
.get();
476 if (!attachment
->ValidForAttachmentType(attachment_type
,
477 manager_
->max_color_attachments_
)) {
478 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
;
481 width
= attachment
->width();
482 height
= attachment
->height();
483 if (width
== 0 || height
== 0) {
484 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
;
486 } else if (manager_
->context_type() != ContextGroup::CONTEXT_TYPE_WEBGL2
) {
487 // TODO(zmo): revisit this if we create ES3 contexts for clients other
489 if (attachment
->width() != width
|| attachment
->height() != height
) {
490 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT
;
494 if (!attachment
->CanRenderTo()) {
495 return GL_FRAMEBUFFER_UNSUPPORTED
;
499 // This does not mean the framebuffer is actually complete. It just means our
501 return GL_FRAMEBUFFER_COMPLETE
;
504 GLenum
Framebuffer::GetStatus(
505 TextureManager
* texture_manager
, GLenum target
) const {
506 // Check if we have this combo already.
507 std::string signature
;
508 if (allow_framebuffer_combo_complete_map_
) {
509 size_t signature_size
= sizeof(target
);
510 for (AttachmentMap::const_iterator it
= attachments_
.begin();
511 it
!= attachments_
.end(); ++it
) {
512 Attachment
* attachment
= it
->second
.get();
513 signature_size
+= sizeof(it
->first
) +
514 attachment
->GetSignatureSize(texture_manager
);
517 signature
.reserve(signature_size
);
518 signature
.append(reinterpret_cast<const char*>(&target
), sizeof(target
));
520 for (AttachmentMap::const_iterator it
= attachments_
.begin();
521 it
!= attachments_
.end(); ++it
) {
522 Attachment
* attachment
= it
->second
.get();
523 signature
.append(reinterpret_cast<const char*>(&it
->first
),
525 attachment
->AddToSignature(texture_manager
, &signature
);
527 DCHECK(signature
.size() == signature_size
);
529 if (!framebuffer_combo_complete_map_
) {
530 framebuffer_combo_complete_map_
= new FramebufferComboCompleteMap();
533 FramebufferComboCompleteMap::const_iterator it
=
534 framebuffer_combo_complete_map_
->find(signature
);
535 if (it
!= framebuffer_combo_complete_map_
->end()) {
536 return GL_FRAMEBUFFER_COMPLETE
;
540 GLenum result
= glCheckFramebufferStatusEXT(target
);
542 // Insert the new result into the combo map.
543 if (allow_framebuffer_combo_complete_map_
&&
544 result
== GL_FRAMEBUFFER_COMPLETE
) {
545 framebuffer_combo_complete_map_
->insert(std::make_pair(signature
, true));
551 bool Framebuffer::IsCleared() const {
552 // are all the attachments cleaared?
553 for (AttachmentMap::const_iterator it
= attachments_
.begin();
554 it
!= attachments_
.end(); ++it
) {
555 Attachment
* attachment
= it
->second
.get();
556 if (!attachment
->cleared()) {
563 GLenum
Framebuffer::GetDrawBuffer(GLenum draw_buffer
) const {
564 GLsizei index
= static_cast<GLsizei
>(
565 draw_buffer
- GL_DRAW_BUFFER0_ARB
);
567 index
< static_cast<GLsizei
>(manager_
->max_draw_buffers_
));
568 return draw_buffers_
[index
];
571 void Framebuffer::SetDrawBuffers(GLsizei n
, const GLenum
* bufs
) {
572 DCHECK(n
<= static_cast<GLsizei
>(manager_
->max_draw_buffers_
));
573 for (GLsizei i
= 0; i
< n
; ++i
)
574 draw_buffers_
[i
] = bufs
[i
];
577 bool Framebuffer::HasAlphaMRT() const {
578 for (uint32 i
= 0; i
< manager_
->max_draw_buffers_
; ++i
) {
579 if (draw_buffers_
[i
] != GL_NONE
) {
580 const Attachment
* attachment
= GetAttachment(draw_buffers_
[i
]);
583 if ((GLES2Util::GetChannelsForFormat(
584 attachment
->internal_format()) & 0x0008) != 0)
591 bool Framebuffer::HasSameInternalFormatsMRT() const {
592 GLenum internal_format
= 0;
593 for (uint32 i
= 0; i
< manager_
->max_draw_buffers_
; ++i
) {
594 if (draw_buffers_
[i
] != GL_NONE
) {
595 const Attachment
* attachment
= GetAttachment(draw_buffers_
[i
]);
598 if (!internal_format
) {
599 internal_format
= attachment
->internal_format();
600 } else if (internal_format
!= attachment
->internal_format()) {
608 void Framebuffer::UnbindRenderbuffer(
609 GLenum target
, Renderbuffer
* renderbuffer
) {
613 for (AttachmentMap::const_iterator it
= attachments_
.begin();
614 it
!= attachments_
.end(); ++it
) {
615 Attachment
* attachment
= it
->second
.get();
616 if (attachment
->IsRenderbuffer(renderbuffer
)) {
617 // TODO(gman): manually detach renderbuffer.
618 // glFramebufferRenderbufferEXT(target, it->first, GL_RENDERBUFFER, 0);
619 AttachRenderbuffer(it
->first
, NULL
);
627 void Framebuffer::UnbindTexture(
628 GLenum target
, TextureRef
* texture_ref
) {
632 for (AttachmentMap::const_iterator it
= attachments_
.begin();
633 it
!= attachments_
.end(); ++it
) {
634 Attachment
* attachment
= it
->second
.get();
635 if (attachment
->IsTexture(texture_ref
)) {
636 // TODO(gman): manually detach texture.
637 // glFramebufferTexture2DEXT(target, it->first, GL_TEXTURE_2D, 0, 0);
638 AttachTexture(it
->first
, NULL
, GL_TEXTURE_2D
, 0, 0);
646 Framebuffer
* FramebufferManager::GetFramebuffer(
648 FramebufferMap::iterator it
= framebuffers_
.find(client_id
);
649 return it
!= framebuffers_
.end() ? it
->second
.get() : NULL
;
652 void FramebufferManager::RemoveFramebuffer(GLuint client_id
) {
653 FramebufferMap::iterator it
= framebuffers_
.find(client_id
);
654 if (it
!= framebuffers_
.end()) {
655 it
->second
->MarkAsDeleted();
656 framebuffers_
.erase(it
);
660 void Framebuffer::DoUnbindGLAttachmentsForWorkaround(GLenum target
) {
661 // Replace all attachments with the default Renderbuffer.
662 for (AttachmentMap::const_iterator it
= attachments_
.begin();
663 it
!= attachments_
.end(); ++it
) {
664 glFramebufferRenderbufferEXT(target
, it
->first
, GL_RENDERBUFFER
, 0);
668 void Framebuffer::AttachRenderbuffer(
669 GLenum attachment
, Renderbuffer
* renderbuffer
) {
670 const Attachment
* a
= GetAttachment(attachment
);
672 a
->DetachFromFramebuffer(this);
674 attachments_
[attachment
] = scoped_refptr
<Attachment
>(
675 new RenderbufferAttachment(renderbuffer
));
677 attachments_
.erase(attachment
);
679 framebuffer_complete_state_count_id_
= 0;
682 void Framebuffer::AttachTexture(
683 GLenum attachment
, TextureRef
* texture_ref
, GLenum target
,
684 GLint level
, GLsizei samples
) {
685 const Attachment
* a
= GetAttachment(attachment
);
687 a
->DetachFromFramebuffer(this);
689 attachments_
[attachment
] = scoped_refptr
<Attachment
>(
690 new TextureAttachment(texture_ref
, target
, level
, samples
));
691 texture_ref
->texture()->AttachToFramebuffer();
693 attachments_
.erase(attachment
);
695 framebuffer_complete_state_count_id_
= 0;
698 const Framebuffer::Attachment
*
699 Framebuffer::GetAttachment(
700 GLenum attachment
) const {
701 AttachmentMap::const_iterator it
= attachments_
.find(attachment
);
702 if (it
!= attachments_
.end()) {
703 return it
->second
.get();
708 const Framebuffer::Attachment
* Framebuffer::GetReadBufferAttachment() const {
709 if (read_buffer_
== GL_NONE
)
711 return GetAttachment(read_buffer_
);
714 void Framebuffer::OnTextureRefDetached(TextureRef
* texture
) {
715 manager_
->OnTextureRefDetached(texture
);
718 void Framebuffer::OnWillRenderTo() const {
719 for (AttachmentMap::const_iterator it
= attachments_
.begin();
720 it
!= attachments_
.end(); ++it
) {
721 it
->second
->OnWillRenderTo();
725 void Framebuffer::OnDidRenderTo() const {
726 for (AttachmentMap::const_iterator it
= attachments_
.begin();
727 it
!= attachments_
.end(); ++it
) {
728 it
->second
->OnDidRenderTo();
732 bool FramebufferManager::GetClientId(
733 GLuint service_id
, GLuint
* client_id
) const {
734 // This doesn't need to be fast. It's only used during slow queries.
735 for (FramebufferMap::const_iterator it
= framebuffers_
.begin();
736 it
!= framebuffers_
.end(); ++it
) {
737 if (it
->second
->service_id() == service_id
) {
738 *client_id
= it
->first
;
745 void FramebufferManager::MarkAttachmentsAsCleared(
746 Framebuffer
* framebuffer
,
747 RenderbufferManager
* renderbuffer_manager
,
748 TextureManager
* texture_manager
) {
750 framebuffer
->MarkAttachmentsAsCleared(renderbuffer_manager
,
753 MarkAsComplete(framebuffer
);
756 void FramebufferManager::MarkAsComplete(
757 Framebuffer
* framebuffer
) {
759 framebuffer
->MarkAsComplete(framebuffer_state_change_count_
);
762 bool FramebufferManager::IsComplete(
763 Framebuffer
* framebuffer
) {
765 return framebuffer
->framebuffer_complete_state_count_id() ==
766 framebuffer_state_change_count_
;
769 void FramebufferManager::OnTextureRefDetached(TextureRef
* texture
) {
770 for (TextureDetachObserverVector::iterator it
=
771 texture_detach_observers_
.begin();
772 it
!= texture_detach_observers_
.end();
774 TextureDetachObserver
* observer
= *it
;
775 observer
->OnTextureRefDetachedFromFramebuffer(texture
);