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 virtual GLsizei width() const OVERRIDE {
52 return renderbuffer_->width();
55 virtual GLsizei height() const OVERRIDE {
56 return renderbuffer_->height();
59 virtual GLenum internal_format() const OVERRIDE {
60 return renderbuffer_->internal_format();
63 virtual GLsizei samples() const OVERRIDE {
64 return renderbuffer_->samples();
67 virtual GLuint object_name() const OVERRIDE {
68 return renderbuffer_->client_id();
71 virtual bool cleared() const OVERRIDE {
72 return renderbuffer_->cleared();
75 virtual void SetCleared(
76 RenderbufferManager* renderbuffer_manager,
77 TextureManager* /* texture_manager */,
78 bool cleared) OVERRIDE {
79 renderbuffer_manager->SetCleared(renderbuffer_.get(), cleared);
82 virtual bool IsTexture(
83 TextureRef* /* texture */) const OVERRIDE {
87 virtual bool IsRenderbuffer(
88 Renderbuffer* renderbuffer) const OVERRIDE {
89 return renderbuffer_.get() == renderbuffer;
92 virtual bool CanRenderTo() const OVERRIDE {
96 virtual void DetachFromFramebuffer(Framebuffer* framebuffer) const OVERRIDE {
97 // Nothing to do for renderbuffers.
100 virtual bool ValidForAttachmentType(
101 GLenum attachment_type, uint32 max_color_attachments) OVERRIDE {
102 uint32 need = GLES2Util::GetChannelsNeededForAttachmentType(
103 attachment_type, max_color_attachments);
104 uint32 have = GLES2Util::GetChannelsForFormat(internal_format());
105 return (need & have) != 0;
108 Renderbuffer* renderbuffer() const {
109 return renderbuffer_.get();
112 virtual void AddToSignature(
113 TextureManager* texture_manager, std::string* signature) const OVERRIDE {
115 renderbuffer_->AddToSignature(signature);
119 virtual ~RenderbufferAttachment() { }
122 scoped_refptr<Renderbuffer> renderbuffer_;
124 DISALLOW_COPY_AND_ASSIGN(RenderbufferAttachment);
127 class TextureAttachment
128 : public Framebuffer::Attachment {
131 TextureRef* texture_ref, GLenum target, GLint level, GLsizei samples)
132 : texture_ref_(texture_ref),
138 virtual GLsizei width() const OVERRIDE {
139 GLsizei temp_width = 0;
140 GLsizei temp_height = 0;
141 texture_ref_->texture()->GetLevelSize(
142 target_, level_, &temp_width, &temp_height);
146 virtual GLsizei height() const OVERRIDE {
147 GLsizei temp_width = 0;
148 GLsizei temp_height = 0;
149 texture_ref_->texture()->GetLevelSize(
150 target_, level_, &temp_width, &temp_height);
154 virtual GLenum internal_format() const OVERRIDE {
155 GLenum temp_type = 0;
156 GLenum temp_internal_format = 0;
157 texture_ref_->texture()->GetLevelType(
158 target_, level_, &temp_type, &temp_internal_format);
159 return temp_internal_format;
162 virtual GLsizei samples() const OVERRIDE {
166 virtual GLuint object_name() const OVERRIDE {
167 return texture_ref_->client_id();
170 virtual bool cleared() const OVERRIDE {
171 return texture_ref_->texture()->IsLevelCleared(target_, level_);
174 virtual void SetCleared(
175 RenderbufferManager* /* renderbuffer_manager */,
176 TextureManager* texture_manager,
177 bool cleared) OVERRIDE {
178 texture_manager->SetLevelCleared(
179 texture_ref_.get(), target_, level_, cleared);
182 virtual bool IsTexture(TextureRef* texture) const OVERRIDE {
183 return texture == texture_ref_.get();
186 virtual bool IsRenderbuffer(
187 Renderbuffer* /* renderbuffer */)
192 TextureRef* texture() const {
193 return texture_ref_.get();
196 virtual bool CanRenderTo() const OVERRIDE {
197 return texture_ref_->texture()->CanRenderTo();
200 virtual void DetachFromFramebuffer(Framebuffer* framebuffer)
202 texture_ref_->texture()->DetachFromFramebuffer();
203 framebuffer->OnTextureRefDetached(texture_ref_.get());
206 virtual bool ValidForAttachmentType(
207 GLenum attachment_type, uint32 max_color_attachments) OVERRIDE {
209 GLenum internal_format = 0;
210 if (!texture_ref_->texture()->GetLevelType(
211 target_, level_, &type, &internal_format)) {
214 uint32 need = GLES2Util::GetChannelsNeededForAttachmentType(
215 attachment_type, max_color_attachments);
216 uint32 have = GLES2Util::GetChannelsForFormat(internal_format);
218 // Workaround for NVIDIA drivers that incorrectly expose these formats as
220 if (internal_format == GL_LUMINANCE || internal_format == GL_ALPHA ||
221 internal_format == GL_LUMINANCE_ALPHA) {
224 return (need & have) != 0;
227 virtual void AddToSignature(
228 TextureManager* texture_manager, std::string* signature) const OVERRIDE {
230 texture_manager->AddToSignature(
231 texture_ref_.get(), target_, level_, signature);
235 virtual ~TextureAttachment() {}
238 scoped_refptr<TextureRef> texture_ref_;
243 DISALLOW_COPY_AND_ASSIGN(TextureAttachment);
246 FramebufferManager::TextureDetachObserver::TextureDetachObserver() {}
248 FramebufferManager::TextureDetachObserver::~TextureDetachObserver() {}
250 FramebufferManager::FramebufferManager(
251 uint32 max_draw_buffers, uint32 max_color_attachments)
252 : framebuffer_state_change_count_(1),
253 framebuffer_count_(0),
255 max_draw_buffers_(max_draw_buffers),
256 max_color_attachments_(max_color_attachments) {
257 DCHECK_GT(max_draw_buffers_, 0u);
258 DCHECK_GT(max_color_attachments_, 0u);
261 FramebufferManager::~FramebufferManager() {
262 DCHECK(framebuffers_.empty());
263 // If this triggers, that means something is keeping a reference to a
264 // Framebuffer belonging to this.
265 CHECK_EQ(framebuffer_count_, 0u);
268 void Framebuffer::MarkAsDeleted() {
270 while (!attachments_.empty()) {
271 Attachment* attachment = attachments_.begin()->second.get();
272 attachment->DetachFromFramebuffer(this);
273 attachments_.erase(attachments_.begin());
277 void FramebufferManager::Destroy(bool have_context) {
278 have_context_ = have_context;
279 framebuffers_.clear();
282 void FramebufferManager::StartTracking(
283 Framebuffer* /* framebuffer */) {
284 ++framebuffer_count_;
287 void FramebufferManager::StopTracking(
288 Framebuffer* /* framebuffer */) {
289 --framebuffer_count_;
292 void FramebufferManager::CreateFramebuffer(
293 GLuint client_id, GLuint service_id) {
294 std::pair<FramebufferMap::iterator, bool> result =
295 framebuffers_.insert(
298 scoped_refptr<Framebuffer>(
299 new Framebuffer(this, service_id))));
300 DCHECK(result.second);
303 Framebuffer::Framebuffer(
304 FramebufferManager* manager, GLuint service_id)
307 service_id_(service_id),
308 has_been_bound_(false),
309 framebuffer_complete_state_count_id_(0) {
310 manager->StartTracking(this);
311 DCHECK_GT(manager->max_draw_buffers_, 0u);
312 draw_buffers_.reset(new GLenum[manager->max_draw_buffers_]);
313 draw_buffers_[0] = GL_COLOR_ATTACHMENT0;
314 for (uint32 i = 1; i < manager->max_draw_buffers_; ++i)
315 draw_buffers_[i] = GL_NONE;
318 Framebuffer::~Framebuffer() {
320 if (manager_->have_context_) {
321 GLuint id = service_id();
322 glDeleteFramebuffersEXT(1, &id);
324 manager_->StopTracking(this);
329 bool Framebuffer::HasUnclearedAttachment(
330 GLenum attachment) const {
331 AttachmentMap::const_iterator it =
332 attachments_.find(attachment);
333 if (it != attachments_.end()) {
334 const Attachment* attachment = it->second.get();
335 return !attachment->cleared();
340 void Framebuffer::MarkAttachmentAsCleared(
341 RenderbufferManager* renderbuffer_manager,
342 TextureManager* texture_manager,
345 AttachmentMap::iterator it = attachments_.find(attachment);
346 if (it != attachments_.end()) {
347 Attachment* a = it->second.get();
348 if (a->cleared() != cleared) {
349 a->SetCleared(renderbuffer_manager,
356 void Framebuffer::MarkAttachmentsAsCleared(
357 RenderbufferManager* renderbuffer_manager,
358 TextureManager* texture_manager,
360 for (AttachmentMap::iterator it = attachments_.begin();
361 it != attachments_.end(); ++it) {
362 Attachment* attachment = it->second.get();
363 if (attachment->cleared() != cleared) {
364 attachment->SetCleared(renderbuffer_manager, texture_manager, cleared);
369 bool Framebuffer::HasDepthAttachment() const {
370 return attachments_.find(GL_DEPTH_STENCIL_ATTACHMENT) != attachments_.end() ||
371 attachments_.find(GL_DEPTH_ATTACHMENT) != attachments_.end();
374 bool Framebuffer::HasStencilAttachment() const {
375 return attachments_.find(GL_DEPTH_STENCIL_ATTACHMENT) != attachments_.end() ||
376 attachments_.find(GL_STENCIL_ATTACHMENT) != attachments_.end();
379 GLenum Framebuffer::GetColorAttachmentFormat() const {
380 AttachmentMap::const_iterator it = attachments_.find(GL_COLOR_ATTACHMENT0);
381 if (it == attachments_.end()) {
384 const Attachment* attachment = it->second.get();
385 return attachment->internal_format();
388 GLenum Framebuffer::IsPossiblyComplete() const {
389 if (attachments_.empty()) {
390 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
395 for (AttachmentMap::const_iterator it = attachments_.begin();
396 it != attachments_.end(); ++it) {
397 GLenum attachment_type = it->first;
398 Attachment* attachment = it->second.get();
399 if (!attachment->ValidForAttachmentType(attachment_type,
400 manager_->max_color_attachments_)) {
401 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
404 width = attachment->width();
405 height = attachment->height();
406 if (width == 0 || height == 0) {
407 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
410 if (attachment->width() != width || attachment->height() != height) {
411 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
415 if (!attachment->CanRenderTo()) {
416 return GL_FRAMEBUFFER_UNSUPPORTED;
420 // This does not mean the framebuffer is actually complete. It just means our
422 return GL_FRAMEBUFFER_COMPLETE;
425 GLenum Framebuffer::GetStatus(
426 TextureManager* texture_manager, GLenum target) const {
427 // Check if we have this combo already.
428 std::string signature;
429 if (allow_framebuffer_combo_complete_map_) {
430 signature = base::StringPrintf("|FBO|target=%04x", target);
431 for (AttachmentMap::const_iterator it = attachments_.begin();
432 it != attachments_.end(); ++it) {
433 Attachment* attachment = it->second.get();
435 base::StringPrintf("|Attachment|attachmentpoint=%04x", it->first);
436 attachment->AddToSignature(texture_manager, &signature);
439 if (!framebuffer_combo_complete_map_) {
440 framebuffer_combo_complete_map_ = new FramebufferComboCompleteMap();
443 FramebufferComboCompleteMap::const_iterator it =
444 framebuffer_combo_complete_map_->find(signature);
445 if (it != framebuffer_combo_complete_map_->end()) {
446 return GL_FRAMEBUFFER_COMPLETE;
450 GLenum result = glCheckFramebufferStatusEXT(target);
452 // Insert the new result into the combo map.
453 if (allow_framebuffer_combo_complete_map_ &&
454 result == GL_FRAMEBUFFER_COMPLETE) {
455 framebuffer_combo_complete_map_->insert(std::make_pair(signature, true));
461 bool Framebuffer::IsCleared() const {
462 // are all the attachments cleaared?
463 for (AttachmentMap::const_iterator it = attachments_.begin();
464 it != attachments_.end(); ++it) {
465 Attachment* attachment = it->second.get();
466 if (!attachment->cleared()) {
473 GLenum Framebuffer::GetDrawBuffer(GLenum draw_buffer) const {
474 GLsizei index = static_cast<GLsizei>(
475 draw_buffer - GL_DRAW_BUFFER0_ARB);
477 index < static_cast<GLsizei>(manager_->max_draw_buffers_));
478 return draw_buffers_[index];
481 void Framebuffer::SetDrawBuffers(GLsizei n, const GLenum* bufs) {
482 DCHECK(n <= static_cast<GLsizei>(manager_->max_draw_buffers_));
483 for (GLsizei i = 0; i < n; ++i)
484 draw_buffers_[i] = bufs[i];
487 bool Framebuffer::HasAlphaMRT() const {
488 for (uint32 i = 0; i < manager_->max_draw_buffers_; ++i) {
489 if (draw_buffers_[i] != GL_NONE) {
490 const Attachment* attachment = GetAttachment(draw_buffers_[i]);
493 if ((GLES2Util::GetChannelsForFormat(
494 attachment->internal_format()) & 0x0008) != 0)
501 void Framebuffer::UnbindRenderbuffer(
502 GLenum target, Renderbuffer* renderbuffer) {
506 for (AttachmentMap::const_iterator it = attachments_.begin();
507 it != attachments_.end(); ++it) {
508 Attachment* attachment = it->second.get();
509 if (attachment->IsRenderbuffer(renderbuffer)) {
510 // TODO(gman): manually detach renderbuffer.
511 // glFramebufferRenderbufferEXT(target, it->first, GL_RENDERBUFFER, 0);
512 AttachRenderbuffer(it->first, NULL);
520 void Framebuffer::UnbindTexture(
521 GLenum target, TextureRef* texture_ref) {
525 for (AttachmentMap::const_iterator it = attachments_.begin();
526 it != attachments_.end(); ++it) {
527 Attachment* attachment = it->second.get();
528 if (attachment->IsTexture(texture_ref)) {
529 // TODO(gman): manually detach texture.
530 // glFramebufferTexture2DEXT(target, it->first, GL_TEXTURE_2D, 0, 0);
531 AttachTexture(it->first, NULL, GL_TEXTURE_2D, 0, 0);
539 Framebuffer* FramebufferManager::GetFramebuffer(
541 FramebufferMap::iterator it = framebuffers_.find(client_id);
542 return it != framebuffers_.end() ? it->second.get() : NULL;
545 void FramebufferManager::RemoveFramebuffer(GLuint client_id) {
546 FramebufferMap::iterator it = framebuffers_.find(client_id);
547 if (it != framebuffers_.end()) {
548 it->second->MarkAsDeleted();
549 framebuffers_.erase(it);
553 void Framebuffer::AttachRenderbuffer(
554 GLenum attachment, Renderbuffer* renderbuffer) {
555 const Attachment* a = GetAttachment(attachment);
557 a->DetachFromFramebuffer(this);
559 attachments_[attachment] = scoped_refptr<Attachment>(
560 new RenderbufferAttachment(renderbuffer));
562 attachments_.erase(attachment);
564 framebuffer_complete_state_count_id_ = 0;
567 void Framebuffer::AttachTexture(
568 GLenum attachment, TextureRef* texture_ref, GLenum target,
569 GLint level, GLsizei samples) {
570 const Attachment* a = GetAttachment(attachment);
572 a->DetachFromFramebuffer(this);
574 attachments_[attachment] = scoped_refptr<Attachment>(
575 new TextureAttachment(texture_ref, target, level, samples));
576 texture_ref->texture()->AttachToFramebuffer();
578 attachments_.erase(attachment);
580 framebuffer_complete_state_count_id_ = 0;
583 const Framebuffer::Attachment*
584 Framebuffer::GetAttachment(
585 GLenum attachment) const {
586 AttachmentMap::const_iterator it = attachments_.find(attachment);
587 if (it != attachments_.end()) {
588 return it->second.get();
593 void Framebuffer::OnTextureRefDetached(TextureRef* texture) {
594 manager_->OnTextureRefDetached(texture);
597 bool FramebufferManager::GetClientId(
598 GLuint service_id, GLuint* client_id) const {
599 // This doesn't need to be fast. It's only used during slow queries.
600 for (FramebufferMap::const_iterator it = framebuffers_.begin();
601 it != framebuffers_.end(); ++it) {
602 if (it->second->service_id() == service_id) {
603 *client_id = it->first;
610 void FramebufferManager::MarkAttachmentsAsCleared(
611 Framebuffer* framebuffer,
612 RenderbufferManager* renderbuffer_manager,
613 TextureManager* texture_manager) {
615 framebuffer->MarkAttachmentsAsCleared(renderbuffer_manager,
618 MarkAsComplete(framebuffer);
621 void FramebufferManager::MarkAsComplete(
622 Framebuffer* framebuffer) {
624 framebuffer->MarkAsComplete(framebuffer_state_change_count_);
627 bool FramebufferManager::IsComplete(
628 Framebuffer* framebuffer) {
630 return framebuffer->framebuffer_complete_state_count_id() ==
631 framebuffer_state_change_count_;
634 void FramebufferManager::OnTextureRefDetached(TextureRef* texture) {
635 for (TextureDetachObserverVector::iterator it =
636 texture_detach_observers_.begin();
637 it != texture_detach_observers_.end();
639 TextureDetachObserver* observer = *it;
640 observer->OnTextureRefDetachedFromFramebuffer(texture);