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 DecoderFramebufferState::DecoderFramebufferState() 17 : clear_state_dirty(false), 18 bound_read_framebuffer(NULL), 19 bound_draw_framebuffer(NULL) { 20 } 21 22 DecoderFramebufferState::~DecoderFramebufferState() { 23 } 24 25 Framebuffer::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) 32 bool Framebuffer::allow_framebuffer_combo_complete_map_ = false; 33 #else 34 bool Framebuffer::allow_framebuffer_combo_complete_map_ = true; 35 #endif 36 37 void Framebuffer::ClearFramebufferCompleteComboMap() { 38 if (framebuffer_combo_complete_map_) { 39 framebuffer_combo_complete_map_->clear(); 40 } 41 } 42 43 class 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 134 class 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 269 FramebufferManager::TextureDetachObserver::TextureDetachObserver() {} 270 271 FramebufferManager::TextureDetachObserver::~TextureDetachObserver() {} 272 273 FramebufferManager::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 284 FramebufferManager::~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 291 void 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 300 void FramebufferManager::Destroy(bool have_context) { 301 have_context_ = have_context; 302 framebuffers_.clear(); 303 } 304 305 void FramebufferManager::StartTracking( 306 Framebuffer* /* framebuffer */) { 307 ++framebuffer_count_; 308 } 309 310 void FramebufferManager::StopTracking( 311 Framebuffer* /* framebuffer */) { 312 --framebuffer_count_; 313 } 314 315 void 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 326 Framebuffer::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 341 Framebuffer::~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 352 bool 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 363 void Framebuffer::MarkAttachmentAsCleared( 364 RenderbufferManager* renderbuffer_manager, 365 TextureManager* texture_manager, 366 GLenum attachment, 367 bool cleared) { 368 AttachmentMap::iterator it = attachments_.find(attachment); 369 if (it != attachments_.end()) { 370 Attachment* a = it->second.get(); 371 if (a->cleared() != cleared) { 372 a->SetCleared(renderbuffer_manager, 373 texture_manager, 374 cleared); 375 } 376 } 377 } 378 379 void Framebuffer::MarkAttachmentsAsCleared( 380 RenderbufferManager* renderbuffer_manager, 381 TextureManager* texture_manager, 382 bool cleared) { 383 for (AttachmentMap::iterator it = attachments_.begin(); 384 it != attachments_.end(); ++it) { 385 Attachment* attachment = it->second.get(); 386 if (attachment->cleared() != cleared) { 387 attachment->SetCleared(renderbuffer_manager, texture_manager, cleared); 388 } 389 } 390 } 391 392 bool Framebuffer::HasDepthAttachment() const { 393 return attachments_.find(GL_DEPTH_STENCIL_ATTACHMENT) != attachments_.end() || 394 attachments_.find(GL_DEPTH_ATTACHMENT) != attachments_.end(); 395 } 396 397 bool Framebuffer::HasStencilAttachment() const { 398 return attachments_.find(GL_DEPTH_STENCIL_ATTACHMENT) != attachments_.end() || 399 attachments_.find(GL_STENCIL_ATTACHMENT) != attachments_.end(); 400 } 401 402 GLenum Framebuffer::GetColorAttachmentFormat() const { 403 AttachmentMap::const_iterator it = attachments_.find(GL_COLOR_ATTACHMENT0); 404 if (it == attachments_.end()) { 405 return 0; 406 } 407 const Attachment* attachment = it->second.get(); 408 return attachment->internal_format(); 409 } 410 411 GLenum Framebuffer::GetColorAttachmentTextureType() const { 412 AttachmentMap::const_iterator it = attachments_.find(GL_COLOR_ATTACHMENT0); 413 if (it == attachments_.end()) { 414 return 0; 415 } 416 const Attachment* attachment = it->second.get(); 417 return attachment->texture_type(); 418 } 419 420 GLenum Framebuffer::IsPossiblyComplete() const { 421 if (attachments_.empty()) { 422 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; 423 } 424 425 GLsizei width = -1; 426 GLsizei height = -1; 427 for (AttachmentMap::const_iterator it = attachments_.begin(); 428 it != attachments_.end(); ++it) { 429 GLenum attachment_type = it->first; 430 Attachment* attachment = it->second.get(); 431 if (!attachment->ValidForAttachmentType(attachment_type, 432 manager_->max_color_attachments_)) { 433 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 434 } 435 if (width < 0) { 436 width = attachment->width(); 437 height = attachment->height(); 438 if (width == 0 || height == 0) { 439 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 440 } 441 } else { 442 if (attachment->width() != width || attachment->height() != height) { 443 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; 444 } 445 } 446 447 if (!attachment->CanRenderTo()) { 448 return GL_FRAMEBUFFER_UNSUPPORTED; 449 } 450 } 451 452 // This does not mean the framebuffer is actually complete. It just means our 453 // checks passed. 454 return GL_FRAMEBUFFER_COMPLETE; 455 } 456 457 GLenum Framebuffer::GetStatus( 458 TextureManager* texture_manager, GLenum target) const { 459 // Check if we have this combo already. 460 std::string signature; 461 if (allow_framebuffer_combo_complete_map_) { 462 signature = base::StringPrintf("|FBO|target=%04x", target); 463 for (AttachmentMap::const_iterator it = attachments_.begin(); 464 it != attachments_.end(); ++it) { 465 Attachment* attachment = it->second.get(); 466 signature += 467 base::StringPrintf("|Attachment|attachmentpoint=%04x", it->first); 468 attachment->AddToSignature(texture_manager, &signature); 469 } 470 471 if (!framebuffer_combo_complete_map_) { 472 framebuffer_combo_complete_map_ = new FramebufferComboCompleteMap(); 473 } 474 475 FramebufferComboCompleteMap::const_iterator it = 476 framebuffer_combo_complete_map_->find(signature); 477 if (it != framebuffer_combo_complete_map_->end()) { 478 return GL_FRAMEBUFFER_COMPLETE; 479 } 480 } 481 482 GLenum result = glCheckFramebufferStatusEXT(target); 483 484 // Insert the new result into the combo map. 485 if (allow_framebuffer_combo_complete_map_ && 486 result == GL_FRAMEBUFFER_COMPLETE) { 487 framebuffer_combo_complete_map_->insert(std::make_pair(signature, true)); 488 } 489 490 return result; 491 } 492 493 bool Framebuffer::IsCleared() const { 494 // are all the attachments cleaared? 495 for (AttachmentMap::const_iterator it = attachments_.begin(); 496 it != attachments_.end(); ++it) { 497 Attachment* attachment = it->second.get(); 498 if (!attachment->cleared()) { 499 return false; 500 } 501 } 502 return true; 503 } 504 505 GLenum Framebuffer::GetDrawBuffer(GLenum draw_buffer) const { 506 GLsizei index = static_cast<GLsizei>( 507 draw_buffer - GL_DRAW_BUFFER0_ARB); 508 CHECK(index >= 0 && 509 index < static_cast<GLsizei>(manager_->max_draw_buffers_)); 510 return draw_buffers_[index]; 511 } 512 513 void Framebuffer::SetDrawBuffers(GLsizei n, const GLenum* bufs) { 514 DCHECK(n <= static_cast<GLsizei>(manager_->max_draw_buffers_)); 515 for (GLsizei i = 0; i < n; ++i) 516 draw_buffers_[i] = bufs[i]; 517 } 518 519 bool Framebuffer::HasAlphaMRT() const { 520 for (uint32 i = 0; i < manager_->max_draw_buffers_; ++i) { 521 if (draw_buffers_[i] != GL_NONE) { 522 const Attachment* attachment = GetAttachment(draw_buffers_[i]); 523 if (!attachment) 524 continue; 525 if ((GLES2Util::GetChannelsForFormat( 526 attachment->internal_format()) & 0x0008) != 0) 527 return true; 528 } 529 } 530 return false; 531 } 532 533 void Framebuffer::UnbindRenderbuffer( 534 GLenum target, Renderbuffer* renderbuffer) { 535 bool done; 536 do { 537 done = true; 538 for (AttachmentMap::const_iterator it = attachments_.begin(); 539 it != attachments_.end(); ++it) { 540 Attachment* attachment = it->second.get(); 541 if (attachment->IsRenderbuffer(renderbuffer)) { 542 // TODO(gman): manually detach renderbuffer. 543 // glFramebufferRenderbufferEXT(target, it->first, GL_RENDERBUFFER, 0); 544 AttachRenderbuffer(it->first, NULL); 545 done = false; 546 break; 547 } 548 } 549 } while (!done); 550 } 551 552 void Framebuffer::UnbindTexture( 553 GLenum target, TextureRef* texture_ref) { 554 bool done; 555 do { 556 done = true; 557 for (AttachmentMap::const_iterator it = attachments_.begin(); 558 it != attachments_.end(); ++it) { 559 Attachment* attachment = it->second.get(); 560 if (attachment->IsTexture(texture_ref)) { 561 // TODO(gman): manually detach texture. 562 // glFramebufferTexture2DEXT(target, it->first, GL_TEXTURE_2D, 0, 0); 563 AttachTexture(it->first, NULL, GL_TEXTURE_2D, 0, 0); 564 done = false; 565 break; 566 } 567 } 568 } while (!done); 569 } 570 571 Framebuffer* FramebufferManager::GetFramebuffer( 572 GLuint client_id) { 573 FramebufferMap::iterator it = framebuffers_.find(client_id); 574 return it != framebuffers_.end() ? it->second.get() : NULL; 575 } 576 577 void FramebufferManager::RemoveFramebuffer(GLuint client_id) { 578 FramebufferMap::iterator it = framebuffers_.find(client_id); 579 if (it != framebuffers_.end()) { 580 it->second->MarkAsDeleted(); 581 framebuffers_.erase(it); 582 } 583 } 584 585 void Framebuffer::AttachRenderbuffer( 586 GLenum attachment, Renderbuffer* renderbuffer) { 587 const Attachment* a = GetAttachment(attachment); 588 if (a) 589 a->DetachFromFramebuffer(this); 590 if (renderbuffer) { 591 attachments_[attachment] = scoped_refptr<Attachment>( 592 new RenderbufferAttachment(renderbuffer)); 593 } else { 594 attachments_.erase(attachment); 595 } 596 framebuffer_complete_state_count_id_ = 0; 597 } 598 599 void Framebuffer::AttachTexture( 600 GLenum attachment, TextureRef* texture_ref, GLenum target, 601 GLint level, GLsizei samples) { 602 const Attachment* a = GetAttachment(attachment); 603 if (a) 604 a->DetachFromFramebuffer(this); 605 if (texture_ref) { 606 attachments_[attachment] = scoped_refptr<Attachment>( 607 new TextureAttachment(texture_ref, target, level, samples)); 608 texture_ref->texture()->AttachToFramebuffer(); 609 } else { 610 attachments_.erase(attachment); 611 } 612 framebuffer_complete_state_count_id_ = 0; 613 } 614 615 const Framebuffer::Attachment* 616 Framebuffer::GetAttachment( 617 GLenum attachment) const { 618 AttachmentMap::const_iterator it = attachments_.find(attachment); 619 if (it != attachments_.end()) { 620 return it->second.get(); 621 } 622 return NULL; 623 } 624 625 void Framebuffer::OnTextureRefDetached(TextureRef* texture) { 626 manager_->OnTextureRefDetached(texture); 627 } 628 629 void Framebuffer::OnWillRenderTo() const { 630 for (AttachmentMap::const_iterator it = attachments_.begin(); 631 it != attachments_.end(); ++it) { 632 it->second->OnWillRenderTo(); 633 } 634 } 635 636 void Framebuffer::OnDidRenderTo() const { 637 for (AttachmentMap::const_iterator it = attachments_.begin(); 638 it != attachments_.end(); ++it) { 639 it->second->OnDidRenderTo(); 640 } 641 } 642 643 bool FramebufferManager::GetClientId( 644 GLuint service_id, GLuint* client_id) const { 645 // This doesn't need to be fast. It's only used during slow queries. 646 for (FramebufferMap::const_iterator it = framebuffers_.begin(); 647 it != framebuffers_.end(); ++it) { 648 if (it->second->service_id() == service_id) { 649 *client_id = it->first; 650 return true; 651 } 652 } 653 return false; 654 } 655 656 void FramebufferManager::MarkAttachmentsAsCleared( 657 Framebuffer* framebuffer, 658 RenderbufferManager* renderbuffer_manager, 659 TextureManager* texture_manager) { 660 DCHECK(framebuffer); 661 framebuffer->MarkAttachmentsAsCleared(renderbuffer_manager, 662 texture_manager, 663 true); 664 MarkAsComplete(framebuffer); 665 } 666 667 void FramebufferManager::MarkAsComplete( 668 Framebuffer* framebuffer) { 669 DCHECK(framebuffer); 670 framebuffer->MarkAsComplete(framebuffer_state_change_count_); 671 } 672 673 bool FramebufferManager::IsComplete( 674 Framebuffer* framebuffer) { 675 DCHECK(framebuffer); 676 return framebuffer->framebuffer_complete_state_count_id() == 677 framebuffer_state_change_count_; 678 } 679 680 void FramebufferManager::OnTextureRefDetached(TextureRef* texture) { 681 for (TextureDetachObserverVector::iterator it = 682 texture_detach_observers_.begin(); 683 it != texture_detach_observers_.end(); 684 ++it) { 685 TextureDetachObserver* observer = *it; 686 observer->OnTextureRefDetachedFromFramebuffer(texture); 687 } 688 } 689 690 } // namespace gles2 691 } // namespace gpu 692 693 694