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/framebuffer_completeness_cache.h"
10 #include "gpu/command_buffer/service/renderbuffer_manager.h"
11 #include "gpu/command_buffer/service/texture_manager.h"
12 #include "ui/gl/gl_bindings.h"
17 DecoderFramebufferState::DecoderFramebufferState()
18 : clear_state_dirty(false),
19 bound_read_framebuffer(NULL
),
20 bound_draw_framebuffer(NULL
) {
23 DecoderFramebufferState::~DecoderFramebufferState() {
26 class RenderbufferAttachment
27 : public Framebuffer::Attachment
{
29 explicit RenderbufferAttachment(
30 Renderbuffer
* renderbuffer
)
31 : renderbuffer_(renderbuffer
) {
34 GLsizei
width() const override
{ return renderbuffer_
->width(); }
36 GLsizei
height() const override
{ return renderbuffer_
->height(); }
38 GLenum
internal_format() const override
{
39 return renderbuffer_
->internal_format();
42 GLenum
texture_type() const override
{ return 0; }
44 GLsizei
samples() const override
{ return renderbuffer_
->samples(); }
46 GLuint
object_name() const override
{ return renderbuffer_
->client_id(); }
48 bool cleared() const override
{ return renderbuffer_
->cleared(); }
50 void SetCleared(RenderbufferManager
* renderbuffer_manager
,
51 TextureManager
* /* texture_manager */,
52 bool cleared
) override
{
53 renderbuffer_manager
->SetCleared(renderbuffer_
.get(), cleared
);
56 bool IsTexture(TextureRef
* /* texture */) const override
{ return false; }
58 bool IsRenderbuffer(Renderbuffer
* renderbuffer
) const override
{
59 return renderbuffer_
.get() == renderbuffer
;
62 bool CanRenderTo() const override
{ return true; }
64 void DetachFromFramebuffer(Framebuffer
* framebuffer
) const override
{
65 // Nothing to do for renderbuffers.
68 bool ValidForAttachmentType(GLenum attachment_type
,
69 uint32 max_color_attachments
) override
{
70 uint32 need
= GLES2Util::GetChannelsNeededForAttachmentType(
71 attachment_type
, max_color_attachments
);
72 uint32 have
= GLES2Util::GetChannelsForFormat(internal_format());
73 return (need
& have
) != 0;
76 Renderbuffer
* renderbuffer() const {
77 return renderbuffer_
.get();
80 size_t GetSignatureSize(TextureManager
* texture_manager
) const override
{
81 return renderbuffer_
->GetSignatureSize();
84 void AddToSignature(TextureManager
* texture_manager
,
85 std::string
* signature
) const override
{
87 renderbuffer_
->AddToSignature(signature
);
90 void OnWillRenderTo() const override
{}
91 void OnDidRenderTo() const override
{}
92 bool FormsFeedbackLoop(TextureRef
* /* texture */,
93 GLint
/*level */) const override
{
98 ~RenderbufferAttachment() override
{}
101 scoped_refptr
<Renderbuffer
> renderbuffer_
;
103 DISALLOW_COPY_AND_ASSIGN(RenderbufferAttachment
);
106 class TextureAttachment
107 : public Framebuffer::Attachment
{
110 TextureRef
* texture_ref
, GLenum target
, GLint level
, GLsizei samples
)
111 : texture_ref_(texture_ref
),
117 GLsizei
width() const override
{
118 GLsizei temp_width
= 0;
119 GLsizei temp_height
= 0;
120 texture_ref_
->texture()->GetLevelSize(
121 target_
, level_
, &temp_width
, &temp_height
, nullptr);
125 GLsizei
height() const override
{
126 GLsizei temp_width
= 0;
127 GLsizei temp_height
= 0;
128 texture_ref_
->texture()->GetLevelSize(
129 target_
, level_
, &temp_width
, &temp_height
, nullptr);
133 GLenum
internal_format() const override
{
134 GLenum temp_type
= 0;
135 GLenum temp_internal_format
= 0;
136 texture_ref_
->texture()->GetLevelType(
137 target_
, level_
, &temp_type
, &temp_internal_format
);
138 return temp_internal_format
;
141 GLenum
texture_type() const override
{
142 GLenum temp_type
= 0;
143 GLenum temp_internal_format
= 0;
144 texture_ref_
->texture()->GetLevelType(
145 target_
, level_
, &temp_type
, &temp_internal_format
);
149 GLsizei
samples() const override
{ return samples_
; }
151 GLuint
object_name() const override
{ return texture_ref_
->client_id(); }
153 bool cleared() const override
{
154 return texture_ref_
->texture()->IsLevelCleared(target_
, level_
);
157 void SetCleared(RenderbufferManager
* /* renderbuffer_manager */,
158 TextureManager
* texture_manager
,
159 bool cleared
) override
{
160 texture_manager
->SetLevelCleared(
161 texture_ref_
.get(), target_
, level_
, cleared
);
164 bool IsTexture(TextureRef
* texture
) const override
{
165 return texture
== texture_ref_
.get();
168 bool IsRenderbuffer(Renderbuffer
* /* renderbuffer */) const override
{
172 TextureRef
* texture() const {
173 return texture_ref_
.get();
176 bool CanRenderTo() const override
{
177 return texture_ref_
->texture()->CanRenderTo();
180 void DetachFromFramebuffer(Framebuffer
* framebuffer
) const override
{
181 texture_ref_
->texture()->DetachFromFramebuffer();
182 framebuffer
->OnTextureRefDetached(texture_ref_
.get());
185 bool ValidForAttachmentType(GLenum attachment_type
,
186 uint32 max_color_attachments
) override
{
188 GLenum internal_format
= 0;
189 if (!texture_ref_
->texture()->GetLevelType(
190 target_
, level_
, &type
, &internal_format
)) {
193 uint32 need
= GLES2Util::GetChannelsNeededForAttachmentType(
194 attachment_type
, max_color_attachments
);
195 uint32 have
= GLES2Util::GetChannelsForFormat(internal_format
);
197 // Workaround for NVIDIA drivers that incorrectly expose these formats as
199 if (internal_format
== GL_LUMINANCE
|| internal_format
== GL_ALPHA
||
200 internal_format
== GL_LUMINANCE_ALPHA
) {
203 return (need
& have
) != 0;
206 size_t GetSignatureSize(TextureManager
* texture_manager
) const override
{
207 return texture_manager
->GetSignatureSize();
210 void AddToSignature(TextureManager
* texture_manager
,
211 std::string
* signature
) const override
{
213 texture_manager
->AddToSignature(
214 texture_ref_
.get(), target_
, level_
, signature
);
217 void OnWillRenderTo() const override
{
218 texture_ref_
->texture()->OnWillModifyPixels();
221 void OnDidRenderTo() const override
{
222 texture_ref_
->texture()->OnDidModifyPixels();
225 bool FormsFeedbackLoop(TextureRef
* texture
, GLint level
) const override
{
226 return texture
== texture_ref_
.get() && level
== level_
;
230 ~TextureAttachment() override
{}
233 scoped_refptr
<TextureRef
> texture_ref_
;
238 DISALLOW_COPY_AND_ASSIGN(TextureAttachment
);
241 FramebufferManager::TextureDetachObserver::TextureDetachObserver() {}
243 FramebufferManager::TextureDetachObserver::~TextureDetachObserver() {}
245 FramebufferManager::FramebufferManager(
246 uint32 max_draw_buffers
,
247 uint32 max_color_attachments
,
248 ContextGroup::ContextType context_type
,
249 const scoped_refptr
<FramebufferCompletenessCache
>&
250 framebuffer_combo_complete_cache
)
251 : framebuffer_state_change_count_(1),
252 framebuffer_count_(0),
254 max_draw_buffers_(max_draw_buffers
),
255 max_color_attachments_(max_color_attachments
),
256 context_type_(context_type
),
257 framebuffer_combo_complete_cache_(framebuffer_combo_complete_cache
) {
258 DCHECK_GT(max_draw_buffers_
, 0u);
259 DCHECK_GT(max_color_attachments_
, 0u);
262 FramebufferManager::~FramebufferManager() {
263 DCHECK(framebuffers_
.empty());
264 // If this triggers, that means something is keeping a reference to a
265 // Framebuffer belonging to this.
266 CHECK_EQ(framebuffer_count_
, 0u);
269 void Framebuffer::MarkAsDeleted() {
271 while (!attachments_
.empty()) {
272 Attachment
* attachment
= attachments_
.begin()->second
.get();
273 attachment
->DetachFromFramebuffer(this);
274 attachments_
.erase(attachments_
.begin());
278 void FramebufferManager::Destroy(bool have_context
) {
279 have_context_
= have_context
;
280 framebuffers_
.clear();
283 void FramebufferManager::StartTracking(
284 Framebuffer
* /* framebuffer */) {
285 ++framebuffer_count_
;
288 void FramebufferManager::StopTracking(
289 Framebuffer
* /* framebuffer */) {
290 --framebuffer_count_
;
293 void FramebufferManager::CreateFramebuffer(
294 GLuint client_id
, GLuint service_id
) {
295 std::pair
<FramebufferMap::iterator
, bool> result
=
296 framebuffers_
.insert(
299 scoped_refptr
<Framebuffer
>(
300 new Framebuffer(this, service_id
))));
301 DCHECK(result
.second
);
304 Framebuffer::Framebuffer(
305 FramebufferManager
* manager
, GLuint service_id
)
308 service_id_(service_id
),
309 has_been_bound_(false),
310 framebuffer_complete_state_count_id_(0),
311 read_buffer_(GL_COLOR_ATTACHMENT0
) {
312 manager
->StartTracking(this);
313 DCHECK_GT(manager
->max_draw_buffers_
, 0u);
314 draw_buffers_
.reset(new GLenum
[manager
->max_draw_buffers_
]);
315 draw_buffers_
[0] = GL_COLOR_ATTACHMENT0
;
316 for (uint32 i
= 1; i
< manager
->max_draw_buffers_
; ++i
)
317 draw_buffers_
[i
] = GL_NONE
;
320 Framebuffer::~Framebuffer() {
322 if (manager_
->have_context_
) {
323 GLuint id
= service_id();
324 glDeleteFramebuffersEXT(1, &id
);
326 manager_
->StopTracking(this);
331 bool Framebuffer::HasUnclearedAttachment(
332 GLenum attachment
) const {
333 AttachmentMap::const_iterator it
=
334 attachments_
.find(attachment
);
335 if (it
!= attachments_
.end()) {
336 const Attachment
* attachment
= it
->second
.get();
337 return !attachment
->cleared();
342 bool Framebuffer::HasUnclearedColorAttachments() const {
343 for (AttachmentMap::const_iterator it
= attachments_
.begin();
344 it
!= attachments_
.end(); ++it
) {
345 if (it
->first
>= GL_COLOR_ATTACHMENT0
&&
346 it
->first
< GL_COLOR_ATTACHMENT0
+ manager_
->max_draw_buffers_
) {
347 const Attachment
* attachment
= it
->second
.get();
348 if (!attachment
->cleared())
355 void Framebuffer::ChangeDrawBuffersHelper(bool recover
) const {
356 scoped_ptr
<GLenum
[]> buffers(new GLenum
[manager_
->max_draw_buffers_
]);
357 for (uint32 i
= 0; i
< manager_
->max_draw_buffers_
; ++i
)
358 buffers
[i
] = GL_NONE
;
359 for (AttachmentMap::const_iterator it
= attachments_
.begin();
360 it
!= attachments_
.end(); ++it
) {
361 if (it
->first
>= GL_COLOR_ATTACHMENT0
&&
362 it
->first
< GL_COLOR_ATTACHMENT0
+ manager_
->max_draw_buffers_
&&
363 !GLES2Util::IsIntegerFormat(it
->second
->internal_format())) {
364 buffers
[it
->first
- GL_COLOR_ATTACHMENT0
] = it
->first
;
367 bool different
= false;
368 for (uint32 i
= 0; i
< manager_
->max_draw_buffers_
; ++i
) {
369 if (buffers
[i
] != draw_buffers_
[i
]) {
376 glDrawBuffersARB(manager_
->max_draw_buffers_
, draw_buffers_
.get());
378 glDrawBuffersARB(manager_
->max_draw_buffers_
, buffers
.get());
382 void Framebuffer::PrepareDrawBuffersForClear() const {
383 bool recover
= false;
384 ChangeDrawBuffersHelper(recover
);
387 void Framebuffer::RestoreDrawBuffersAfterClear() const {
389 ChangeDrawBuffersHelper(recover
);
392 void Framebuffer::ClearIntegerBuffers() {
393 for (AttachmentMap::const_iterator it
= attachments_
.begin();
394 it
!= attachments_
.end(); ++it
) {
395 GLenum internal_format
= it
->second
->internal_format();
396 if (it
->first
>= GL_COLOR_ATTACHMENT0
&&
397 it
->first
< GL_COLOR_ATTACHMENT0
+ manager_
->max_draw_buffers_
&&
398 !it
->second
->cleared() &&
399 GLES2Util::IsIntegerFormat(internal_format
)) {
400 GLint drawbuffer
= it
->first
- GL_COLOR_ATTACHMENT0
;
401 if (GLES2Util::IsUnsignedIntegerFormat(internal_format
)) {
402 const static GLuint kZero
[] = { 0u, 0u, 0u, 0u };
403 glClearBufferuiv(GL_COLOR
, drawbuffer
, kZero
);
404 } else { // IsUnsignedIntegerFormat(internal_format)
405 const static GLint kZero
[] = { 0, 0, 0, 0 };
406 glClearBufferiv(GL_COLOR
, drawbuffer
, kZero
);
412 void Framebuffer::MarkAttachmentAsCleared(
413 RenderbufferManager
* renderbuffer_manager
,
414 TextureManager
* texture_manager
,
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
,
428 void Framebuffer::MarkAttachmentsAsCleared(
429 RenderbufferManager
* renderbuffer_manager
,
430 TextureManager
* texture_manager
,
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
);
441 bool Framebuffer::HasDepthAttachment() const {
442 return attachments_
.find(GL_DEPTH_STENCIL_ATTACHMENT
) != attachments_
.end() ||
443 attachments_
.find(GL_DEPTH_ATTACHMENT
) != attachments_
.end();
446 bool Framebuffer::HasStencilAttachment() const {
447 return attachments_
.find(GL_DEPTH_STENCIL_ATTACHMENT
) != attachments_
.end() ||
448 attachments_
.find(GL_STENCIL_ATTACHMENT
) != attachments_
.end();
451 GLenum
Framebuffer::GetReadBufferInternalFormat() const {
452 if (read_buffer_
== GL_NONE
)
454 AttachmentMap::const_iterator it
= attachments_
.find(read_buffer_
);
455 if (it
== attachments_
.end()) {
458 const Attachment
* attachment
= it
->second
.get();
459 return attachment
->internal_format();
462 GLenum
Framebuffer::GetReadBufferTextureType() const {
463 if (read_buffer_
== GL_NONE
)
465 AttachmentMap::const_iterator it
= attachments_
.find(read_buffer_
);
466 if (it
== attachments_
.end()) {
469 const Attachment
* attachment
= it
->second
.get();
470 return attachment
->texture_type();
473 GLenum
Framebuffer::IsPossiblyComplete() const {
474 if (attachments_
.empty()) {
475 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
;
480 for (AttachmentMap::const_iterator it
= attachments_
.begin();
481 it
!= attachments_
.end(); ++it
) {
482 GLenum attachment_type
= it
->first
;
483 Attachment
* attachment
= it
->second
.get();
484 if (!attachment
->ValidForAttachmentType(attachment_type
,
485 manager_
->max_color_attachments_
)) {
486 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
;
489 width
= attachment
->width();
490 height
= attachment
->height();
491 if (width
== 0 || height
== 0) {
492 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
;
494 } else if (manager_
->context_type() != ContextGroup::CONTEXT_TYPE_WEBGL2
) {
495 // TODO(zmo): revisit this if we create ES3 contexts for clients other
497 if (attachment
->width() != width
|| attachment
->height() != height
) {
498 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT
;
502 if (!attachment
->CanRenderTo()) {
503 return GL_FRAMEBUFFER_UNSUPPORTED
;
507 // This does not mean the framebuffer is actually complete. It just means our
509 return GL_FRAMEBUFFER_COMPLETE
;
512 GLenum
Framebuffer::GetStatus(
513 TextureManager
* texture_manager
, GLenum target
) const {
514 if (!manager_
->GetFramebufferComboCompleteCache()) {
515 return glCheckFramebufferStatusEXT(target
);
517 // Check if we have this combo already.
518 std::string signature
;
520 size_t signature_size
= sizeof(target
);
521 for (AttachmentMap::const_iterator it
= attachments_
.begin();
522 it
!= attachments_
.end(); ++it
) {
523 Attachment
* attachment
= it
->second
.get();
525 sizeof(it
->first
) + attachment
->GetSignatureSize(texture_manager
);
528 signature
.reserve(signature_size
);
529 signature
.append(reinterpret_cast<const char*>(&target
), sizeof(target
));
531 for (AttachmentMap::const_iterator it
= attachments_
.begin();
532 it
!= attachments_
.end(); ++it
) {
533 Attachment
* attachment
= it
->second
.get();
534 signature
.append(reinterpret_cast<const char*>(&it
->first
),
536 attachment
->AddToSignature(texture_manager
, &signature
);
538 DCHECK(signature
.size() == signature_size
);
540 if (manager_
->GetFramebufferComboCompleteCache()->IsComplete(signature
)) {
541 return GL_FRAMEBUFFER_COMPLETE
;
544 GLenum result
= glCheckFramebufferStatusEXT(target
);
546 if (result
== GL_FRAMEBUFFER_COMPLETE
) {
547 manager_
->GetFramebufferComboCompleteCache()->SetComplete(signature
);
553 bool Framebuffer::IsCleared() const {
554 // are all the attachments cleaared?
555 for (AttachmentMap::const_iterator it
= attachments_
.begin();
556 it
!= attachments_
.end(); ++it
) {
557 Attachment
* attachment
= it
->second
.get();
558 if (!attachment
->cleared()) {
565 GLenum
Framebuffer::GetDrawBuffer(GLenum draw_buffer
) const {
566 GLsizei index
= static_cast<GLsizei
>(
567 draw_buffer
- GL_DRAW_BUFFER0_ARB
);
569 index
< static_cast<GLsizei
>(manager_
->max_draw_buffers_
));
570 return draw_buffers_
[index
];
573 void Framebuffer::SetDrawBuffers(GLsizei n
, const GLenum
* bufs
) {
574 DCHECK(n
<= static_cast<GLsizei
>(manager_
->max_draw_buffers_
));
575 for (GLsizei i
= 0; i
< n
; ++i
)
576 draw_buffers_
[i
] = bufs
[i
];
579 bool Framebuffer::HasAlphaMRT() const {
580 for (uint32 i
= 0; i
< manager_
->max_draw_buffers_
; ++i
) {
581 if (draw_buffers_
[i
] != GL_NONE
) {
582 const Attachment
* attachment
= GetAttachment(draw_buffers_
[i
]);
585 if ((GLES2Util::GetChannelsForFormat(
586 attachment
->internal_format()) & 0x0008) != 0)
593 bool Framebuffer::HasSameInternalFormatsMRT() const {
594 GLenum internal_format
= 0;
595 for (uint32 i
= 0; i
< manager_
->max_draw_buffers_
; ++i
) {
596 if (draw_buffers_
[i
] != GL_NONE
) {
597 const Attachment
* attachment
= GetAttachment(draw_buffers_
[i
]);
600 if (!internal_format
) {
601 internal_format
= attachment
->internal_format();
602 } else if (internal_format
!= attachment
->internal_format()) {
610 void Framebuffer::UnbindRenderbuffer(
611 GLenum target
, Renderbuffer
* renderbuffer
) {
615 for (AttachmentMap::const_iterator it
= attachments_
.begin();
616 it
!= attachments_
.end(); ++it
) {
617 Attachment
* attachment
= it
->second
.get();
618 if (attachment
->IsRenderbuffer(renderbuffer
)) {
619 // TODO(gman): manually detach renderbuffer.
620 // glFramebufferRenderbufferEXT(target, it->first, GL_RENDERBUFFER, 0);
621 AttachRenderbuffer(it
->first
, NULL
);
629 void Framebuffer::UnbindTexture(
630 GLenum target
, TextureRef
* texture_ref
) {
634 for (AttachmentMap::const_iterator it
= attachments_
.begin();
635 it
!= attachments_
.end(); ++it
) {
636 Attachment
* attachment
= it
->second
.get();
637 if (attachment
->IsTexture(texture_ref
)) {
638 // TODO(gman): manually detach texture.
639 // glFramebufferTexture2DEXT(target, it->first, GL_TEXTURE_2D, 0, 0);
640 AttachTexture(it
->first
, NULL
, GL_TEXTURE_2D
, 0, 0);
648 Framebuffer
* FramebufferManager::GetFramebuffer(
650 FramebufferMap::iterator it
= framebuffers_
.find(client_id
);
651 return it
!= framebuffers_
.end() ? it
->second
.get() : NULL
;
654 void FramebufferManager::RemoveFramebuffer(GLuint client_id
) {
655 FramebufferMap::iterator it
= framebuffers_
.find(client_id
);
656 if (it
!= framebuffers_
.end()) {
657 it
->second
->MarkAsDeleted();
658 framebuffers_
.erase(it
);
662 void Framebuffer::DoUnbindGLAttachmentsForWorkaround(GLenum target
) {
663 // Replace all attachments with the default Renderbuffer.
664 for (AttachmentMap::const_iterator it
= attachments_
.begin();
665 it
!= attachments_
.end(); ++it
) {
666 glFramebufferRenderbufferEXT(target
, it
->first
, GL_RENDERBUFFER
, 0);
670 void Framebuffer::AttachRenderbuffer(
671 GLenum attachment
, Renderbuffer
* renderbuffer
) {
672 const Attachment
* a
= GetAttachment(attachment
);
674 a
->DetachFromFramebuffer(this);
676 attachments_
[attachment
] = scoped_refptr
<Attachment
>(
677 new RenderbufferAttachment(renderbuffer
));
679 attachments_
.erase(attachment
);
681 framebuffer_complete_state_count_id_
= 0;
684 void Framebuffer::AttachTexture(
685 GLenum attachment
, TextureRef
* texture_ref
, GLenum target
,
686 GLint level
, GLsizei samples
) {
687 const Attachment
* a
= GetAttachment(attachment
);
689 a
->DetachFromFramebuffer(this);
691 attachments_
[attachment
] = scoped_refptr
<Attachment
>(
692 new TextureAttachment(texture_ref
, target
, level
, samples
));
693 texture_ref
->texture()->AttachToFramebuffer();
695 attachments_
.erase(attachment
);
697 framebuffer_complete_state_count_id_
= 0;
700 const Framebuffer::Attachment
*
701 Framebuffer::GetAttachment(
702 GLenum attachment
) const {
703 AttachmentMap::const_iterator it
= attachments_
.find(attachment
);
704 if (it
!= attachments_
.end()) {
705 return it
->second
.get();
710 const Framebuffer::Attachment
* Framebuffer::GetReadBufferAttachment() const {
711 if (read_buffer_
== GL_NONE
)
713 return GetAttachment(read_buffer_
);
716 void Framebuffer::OnTextureRefDetached(TextureRef
* texture
) {
717 manager_
->OnTextureRefDetached(texture
);
720 void Framebuffer::OnWillRenderTo(GLenum attachment
) const {
721 for (AttachmentMap::const_iterator it
= attachments_
.begin();
722 it
!= attachments_
.end(); ++it
) {
723 if (attachment
== 0 || attachment
== it
->first
) {
724 it
->second
->OnWillRenderTo();
729 void Framebuffer::OnDidRenderTo(GLenum attachment
) const {
730 for (AttachmentMap::const_iterator it
= attachments_
.begin();
731 it
!= attachments_
.end(); ++it
) {
732 if (attachment
== 0 || attachment
== it
->first
) {
733 it
->second
->OnDidRenderTo();
738 bool FramebufferManager::GetClientId(
739 GLuint service_id
, GLuint
* client_id
) const {
740 // This doesn't need to be fast. It's only used during slow queries.
741 for (FramebufferMap::const_iterator it
= framebuffers_
.begin();
742 it
!= framebuffers_
.end(); ++it
) {
743 if (it
->second
->service_id() == service_id
) {
744 *client_id
= it
->first
;
751 void FramebufferManager::MarkAttachmentsAsCleared(
752 Framebuffer
* framebuffer
,
753 RenderbufferManager
* renderbuffer_manager
,
754 TextureManager
* texture_manager
) {
756 framebuffer
->MarkAttachmentsAsCleared(renderbuffer_manager
,
759 MarkAsComplete(framebuffer
);
762 void FramebufferManager::MarkAsComplete(
763 Framebuffer
* framebuffer
) {
765 framebuffer
->MarkAsComplete(framebuffer_state_change_count_
);
768 bool FramebufferManager::IsComplete(
769 Framebuffer
* framebuffer
) {
771 return framebuffer
->framebuffer_complete_state_count_id() ==
772 framebuffer_state_change_count_
;
775 void FramebufferManager::OnTextureRefDetached(TextureRef
* texture
) {
776 for (TextureDetachObserverVector::iterator it
=
777 texture_detach_observers_
.begin();
778 it
!= texture_detach_observers_
.end();
780 TextureDetachObserver
* observer
= *it
;
781 observer
->OnTextureRefDetachedFromFramebuffer(texture
);