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/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 Framebuffer::FramebufferComboCompleteMap
*
17 Framebuffer::framebuffer_combo_complete_map_
;
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;
25 bool Framebuffer::allow_framebuffer_combo_complete_map_
= true;
28 void Framebuffer::ClearFramebufferCompleteComboMap() {
29 if (framebuffer_combo_complete_map_
) {
30 framebuffer_combo_complete_map_
->clear();
34 class RenderbufferAttachment
35 : public Framebuffer::Attachment
{
37 explicit RenderbufferAttachment(
38 Renderbuffer
* renderbuffer
)
39 : renderbuffer_(renderbuffer
) {
42 virtual GLsizei
width() const OVERRIDE
{
43 return renderbuffer_
->width();
46 virtual GLsizei
height() const OVERRIDE
{
47 return renderbuffer_
->height();
50 virtual GLenum
internal_format() const OVERRIDE
{
51 return renderbuffer_
->internal_format();
54 virtual GLsizei
samples() const OVERRIDE
{
55 return renderbuffer_
->samples();
58 virtual GLuint
object_name() const OVERRIDE
{
59 return renderbuffer_
->client_id();
62 virtual bool cleared() const OVERRIDE
{
63 return renderbuffer_
->cleared();
66 virtual void SetCleared(
67 RenderbufferManager
* renderbuffer_manager
,
68 TextureManager
* /* texture_manager */,
69 bool cleared
) OVERRIDE
{
70 renderbuffer_manager
->SetCleared(renderbuffer_
, cleared
);
73 virtual bool IsTexture(
74 TextureRef
* /* texture */) const OVERRIDE
{
78 virtual bool IsRenderbuffer(
79 Renderbuffer
* renderbuffer
) const OVERRIDE
{
80 return renderbuffer_
== renderbuffer
;
83 virtual bool CanRenderTo() const OVERRIDE
{
87 virtual void DetachFromFramebuffer() const OVERRIDE
{
88 // Nothing to do for renderbuffers.
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;
99 Renderbuffer
* renderbuffer() const {
100 return renderbuffer_
.get();
103 virtual void AddToSignature(
104 TextureManager
* texture_manager
, std::string
* signature
) const OVERRIDE
{
106 renderbuffer_
->AddToSignature(signature
);
110 virtual ~RenderbufferAttachment() { }
113 scoped_refptr
<Renderbuffer
> renderbuffer_
;
115 DISALLOW_COPY_AND_ASSIGN(RenderbufferAttachment
);
118 class TextureAttachment
119 : public Framebuffer::Attachment
{
122 TextureRef
* texture_ref
, GLenum target
, GLint level
)
123 : texture_ref_(texture_ref
),
128 virtual GLsizei
width() const OVERRIDE
{
129 GLsizei temp_width
= 0;
130 GLsizei temp_height
= 0;
131 texture_ref_
->texture()->GetLevelSize(
132 target_
, level_
, &temp_width
, &temp_height
);
136 virtual GLsizei
height() const OVERRIDE
{
137 GLsizei temp_width
= 0;
138 GLsizei temp_height
= 0;
139 texture_ref_
->texture()->GetLevelSize(
140 target_
, level_
, &temp_width
, &temp_height
);
144 virtual GLenum
internal_format() const OVERRIDE
{
145 GLenum temp_type
= 0;
146 GLenum temp_internal_format
= 0;
147 texture_ref_
->texture()->GetLevelType(
148 target_
, level_
, &temp_type
, &temp_internal_format
);
149 return temp_internal_format
;
152 virtual GLsizei
samples() const OVERRIDE
{
156 virtual GLuint
object_name() const OVERRIDE
{
157 return texture_ref_
->client_id();
160 virtual bool cleared() const OVERRIDE
{
161 return texture_ref_
->texture()->IsLevelCleared(target_
, level_
);
164 virtual void SetCleared(
165 RenderbufferManager
* /* renderbuffer_manager */,
166 TextureManager
* texture_manager
,
167 bool cleared
) OVERRIDE
{
168 texture_manager
->SetLevelCleared(texture_ref_
, target_
, level_
, cleared
);
171 virtual bool IsTexture(TextureRef
* texture
) const OVERRIDE
{
172 return texture
== texture_ref_
.get();
175 virtual bool IsRenderbuffer(
176 Renderbuffer
* /* renderbuffer */)
181 TextureRef
* texture() const {
182 return texture_ref_
.get();
185 virtual bool CanRenderTo() const OVERRIDE
{
186 return texture_ref_
->texture()->CanRenderTo();
189 virtual void DetachFromFramebuffer() const OVERRIDE
{
190 texture_ref_
->texture()->DetachFromFramebuffer();
193 virtual bool ValidForAttachmentType(
194 GLenum attachment_type
, uint32 max_color_attachments
) OVERRIDE
{
196 GLenum internal_format
= 0;
197 if (!texture_ref_
->texture()->GetLevelType(
198 target_
, level_
, &type
, &internal_format
)) {
201 uint32 need
= GLES2Util::GetChannelsNeededForAttachmentType(
202 attachment_type
, max_color_attachments
);
203 uint32 have
= GLES2Util::GetChannelsForFormat(internal_format
);
204 return (need
& have
) != 0;
207 virtual void AddToSignature(
208 TextureManager
* texture_manager
, std::string
* signature
) const OVERRIDE
{
210 texture_manager
->AddToSignature(texture_ref_
, target_
, level_
, signature
);
214 virtual ~TextureAttachment() {}
217 scoped_refptr
<TextureRef
> texture_ref_
;
221 DISALLOW_COPY_AND_ASSIGN(TextureAttachment
);
224 FramebufferManager::FramebufferManager(
225 uint32 max_draw_buffers
, uint32 max_color_attachments
)
226 : framebuffer_state_change_count_(1),
227 framebuffer_count_(0),
229 max_draw_buffers_(max_draw_buffers
),
230 max_color_attachments_(max_color_attachments
) {
231 DCHECK_GT(max_draw_buffers_
, 0u);
232 DCHECK_GT(max_color_attachments_
, 0u);
235 FramebufferManager::~FramebufferManager() {
236 DCHECK(framebuffers_
.empty());
237 // If this triggers, that means something is keeping a reference to a
238 // Framebuffer belonging to this.
239 CHECK_EQ(framebuffer_count_
, 0u);
242 void Framebuffer::MarkAsDeleted() {
244 while (!attachments_
.empty()) {
245 Attachment
* attachment
= attachments_
.begin()->second
.get();
246 attachment
->DetachFromFramebuffer();
247 attachments_
.erase(attachments_
.begin());
251 void FramebufferManager::Destroy(bool have_context
) {
252 have_context_
= have_context
;
253 framebuffers_
.clear();
256 void FramebufferManager::StartTracking(
257 Framebuffer
* /* framebuffer */) {
258 ++framebuffer_count_
;
261 void FramebufferManager::StopTracking(
262 Framebuffer
* /* framebuffer */) {
263 --framebuffer_count_
;
266 void FramebufferManager::CreateFramebuffer(
267 GLuint client_id
, GLuint service_id
) {
268 std::pair
<FramebufferMap::iterator
, bool> result
=
269 framebuffers_
.insert(
272 scoped_refptr
<Framebuffer
>(
273 new Framebuffer(this, service_id
))));
274 DCHECK(result
.second
);
277 Framebuffer::Framebuffer(
278 FramebufferManager
* manager
, GLuint service_id
)
281 service_id_(service_id
),
282 has_been_bound_(false),
283 framebuffer_complete_state_count_id_(0) {
284 manager
->StartTracking(this);
285 DCHECK_GT(manager
->max_draw_buffers_
, 0u);
286 draw_buffers_
.reset(new GLenum
[manager
->max_draw_buffers_
]);
287 draw_buffers_
[0] = GL_COLOR_ATTACHMENT0
;
288 for (uint32 i
= 1; i
< manager
->max_draw_buffers_
; ++i
)
289 draw_buffers_
[i
] = GL_NONE
;
292 Framebuffer::~Framebuffer() {
294 if (manager_
->have_context_
) {
295 GLuint id
= service_id();
296 glDeleteFramebuffersEXT(1, &id
);
298 manager_
->StopTracking(this);
303 bool Framebuffer::HasUnclearedAttachment(
304 GLenum attachment
) const {
305 AttachmentMap::const_iterator it
=
306 attachments_
.find(attachment
);
307 if (it
!= attachments_
.end()) {
308 const Attachment
* attachment
= it
->second
;
309 return !attachment
->cleared();
314 void Framebuffer::MarkAttachmentAsCleared(
315 RenderbufferManager
* renderbuffer_manager
,
316 TextureManager
* texture_manager
,
319 AttachmentMap::iterator it
= attachments_
.find(attachment
);
320 if (it
!= attachments_
.end()) {
321 Attachment
* a
= it
->second
;
322 if (a
->cleared() != cleared
) {
323 a
->SetCleared(renderbuffer_manager
,
330 void Framebuffer::MarkAttachmentsAsCleared(
331 RenderbufferManager
* renderbuffer_manager
,
332 TextureManager
* texture_manager
,
334 for (AttachmentMap::iterator it
= attachments_
.begin();
335 it
!= attachments_
.end(); ++it
) {
336 Attachment
* attachment
= it
->second
;
337 if (attachment
->cleared() != cleared
) {
338 attachment
->SetCleared(renderbuffer_manager
, texture_manager
, cleared
);
343 bool Framebuffer::HasDepthAttachment() const {
344 return attachments_
.find(GL_DEPTH_STENCIL_ATTACHMENT
) != attachments_
.end() ||
345 attachments_
.find(GL_DEPTH_ATTACHMENT
) != attachments_
.end();
348 bool Framebuffer::HasStencilAttachment() const {
349 return attachments_
.find(GL_DEPTH_STENCIL_ATTACHMENT
) != attachments_
.end() ||
350 attachments_
.find(GL_STENCIL_ATTACHMENT
) != attachments_
.end();
353 GLenum
Framebuffer::GetColorAttachmentFormat() const {
354 AttachmentMap::const_iterator it
= attachments_
.find(GL_COLOR_ATTACHMENT0
);
355 if (it
== attachments_
.end()) {
358 const Attachment
* attachment
= it
->second
;
359 return attachment
->internal_format();
362 GLenum
Framebuffer::IsPossiblyComplete() const {
363 if (attachments_
.empty()) {
364 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
;
369 for (AttachmentMap::const_iterator it
= attachments_
.begin();
370 it
!= attachments_
.end(); ++it
) {
371 GLenum attachment_type
= it
->first
;
372 Attachment
* attachment
= it
->second
;
373 if (!attachment
->ValidForAttachmentType(
374 attachment_type
, manager_
->max_color_attachments_
)) {
375 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
;
378 width
= attachment
->width();
379 height
= attachment
->height();
380 if (width
== 0 || height
== 0) {
381 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
;
384 if (attachment
->width() != width
|| attachment
->height() != height
) {
385 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT
;
389 if (!attachment
->CanRenderTo()) {
390 return GL_FRAMEBUFFER_UNSUPPORTED
;
394 // This does not mean the framebuffer is actually complete. It just means our
396 return GL_FRAMEBUFFER_COMPLETE
;
399 GLenum
Framebuffer::GetStatus(
400 TextureManager
* texture_manager
, GLenum target
) const {
401 // Check if we have this combo already.
402 std::string signature
;
403 if (allow_framebuffer_combo_complete_map_
) {
404 signature
= base::StringPrintf("|FBO|target=%04x", target
);
405 for (AttachmentMap::const_iterator it
= attachments_
.begin();
406 it
!= attachments_
.end(); ++it
) {
407 Attachment
* attachment
= it
->second
;
408 signature
+= base::StringPrintf(
409 "|Attachment|attachmentpoint=%04x", it
->first
);
410 attachment
->AddToSignature(texture_manager
, &signature
);
413 if (!framebuffer_combo_complete_map_
) {
414 framebuffer_combo_complete_map_
= new FramebufferComboCompleteMap();
417 FramebufferComboCompleteMap::const_iterator it
=
418 framebuffer_combo_complete_map_
->find(signature
);
419 if (it
!= framebuffer_combo_complete_map_
->end()) {
420 return GL_FRAMEBUFFER_COMPLETE
;
424 GLenum result
= glCheckFramebufferStatusEXT(target
);
426 // Insert the new result into the combo map.
427 if (allow_framebuffer_combo_complete_map_
&&
428 result
== GL_FRAMEBUFFER_COMPLETE
) {
429 framebuffer_combo_complete_map_
->insert(std::make_pair(signature
, true));
435 bool Framebuffer::IsCleared() const {
436 // are all the attachments cleaared?
437 for (AttachmentMap::const_iterator it
= attachments_
.begin();
438 it
!= attachments_
.end(); ++it
) {
439 Attachment
* attachment
= it
->second
;
440 if (!attachment
->cleared()) {
447 GLenum
Framebuffer::GetDrawBuffer(GLenum draw_buffer
) const {
448 GLsizei index
= static_cast<GLsizei
>(
449 draw_buffer
- GL_DRAW_BUFFER0_ARB
);
451 index
< static_cast<GLsizei
>(manager_
->max_draw_buffers_
));
452 return draw_buffers_
[index
];
455 void Framebuffer::SetDrawBuffers(GLsizei n
, const GLenum
* bufs
) {
456 DCHECK(n
<= static_cast<GLsizei
>(manager_
->max_draw_buffers_
));
457 for (GLsizei i
= 0; i
< n
; ++i
)
458 draw_buffers_
[i
] = bufs
[i
];
461 void Framebuffer::UnbindRenderbuffer(
462 GLenum target
, Renderbuffer
* renderbuffer
) {
466 for (AttachmentMap::const_iterator it
= attachments_
.begin();
467 it
!= attachments_
.end(); ++it
) {
468 Attachment
* attachment
= it
->second
;
469 if (attachment
->IsRenderbuffer(renderbuffer
)) {
470 // TODO(gman): manually detach renderbuffer.
471 // glFramebufferRenderbufferEXT(target, it->first, GL_RENDERBUFFER, 0);
472 AttachRenderbuffer(it
->first
, NULL
);
480 void Framebuffer::UnbindTexture(
481 GLenum target
, TextureRef
* texture_ref
) {
485 for (AttachmentMap::const_iterator it
= attachments_
.begin();
486 it
!= attachments_
.end(); ++it
) {
487 Attachment
* attachment
= it
->second
;
488 if (attachment
->IsTexture(texture_ref
)) {
489 // TODO(gman): manually detach texture.
490 // glFramebufferTexture2DEXT(target, it->first, GL_TEXTURE_2D, 0, 0);
491 AttachTexture(it
->first
, NULL
, GL_TEXTURE_2D
, 0);
499 Framebuffer
* FramebufferManager::GetFramebuffer(
501 FramebufferMap::iterator it
= framebuffers_
.find(client_id
);
502 return it
!= framebuffers_
.end() ? it
->second
: NULL
;
505 void FramebufferManager::RemoveFramebuffer(GLuint client_id
) {
506 FramebufferMap::iterator it
= framebuffers_
.find(client_id
);
507 if (it
!= framebuffers_
.end()) {
508 it
->second
->MarkAsDeleted();
509 framebuffers_
.erase(it
);
513 void Framebuffer::AttachRenderbuffer(
514 GLenum attachment
, Renderbuffer
* renderbuffer
) {
515 const Attachment
* a
= GetAttachment(attachment
);
517 a
->DetachFromFramebuffer();
519 attachments_
[attachment
] = scoped_refptr
<Attachment
>(
520 new RenderbufferAttachment(renderbuffer
));
522 attachments_
.erase(attachment
);
524 framebuffer_complete_state_count_id_
= 0;
527 void Framebuffer::AttachTexture(
528 GLenum attachment
, TextureRef
* texture_ref
, GLenum target
,
530 const Attachment
* a
= GetAttachment(attachment
);
532 a
->DetachFromFramebuffer();
534 attachments_
[attachment
] = scoped_refptr
<Attachment
>(
535 new TextureAttachment(texture_ref
, target
, level
));
536 texture_ref
->texture()->AttachToFramebuffer();
538 attachments_
.erase(attachment
);
540 framebuffer_complete_state_count_id_
= 0;
543 const Framebuffer::Attachment
*
544 Framebuffer::GetAttachment(
545 GLenum attachment
) const {
546 AttachmentMap::const_iterator it
= attachments_
.find(attachment
);
547 if (it
!= attachments_
.end()) {
553 bool FramebufferManager::GetClientId(
554 GLuint service_id
, GLuint
* client_id
) const {
555 // This doesn't need to be fast. It's only used during slow queries.
556 for (FramebufferMap::const_iterator it
= framebuffers_
.begin();
557 it
!= framebuffers_
.end(); ++it
) {
558 if (it
->second
->service_id() == service_id
) {
559 *client_id
= it
->first
;
566 void FramebufferManager::MarkAttachmentsAsCleared(
567 Framebuffer
* framebuffer
,
568 RenderbufferManager
* renderbuffer_manager
,
569 TextureManager
* texture_manager
) {
571 framebuffer
->MarkAttachmentsAsCleared(renderbuffer_manager
,
574 MarkAsComplete(framebuffer
);
577 void FramebufferManager::MarkAsComplete(
578 Framebuffer
* framebuffer
) {
580 framebuffer
->MarkAsComplete(framebuffer_state_change_count_
);
583 bool FramebufferManager::IsComplete(
584 Framebuffer
* framebuffer
) {
586 return framebuffer
->framebuffer_complete_state_count_id() ==
587 framebuffer_state_change_count_
;