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