- add sources.
[platform/framework/web/crosswalk.git] / src / gpu / command_buffer / service / framebuffer_manager.cc
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 GLsizei samples() const OVERRIDE {
64     return renderbuffer_->samples();
65   }
66
67   virtual GLuint object_name() const OVERRIDE {
68     return renderbuffer_->client_id();
69   }
70
71   virtual bool cleared() const OVERRIDE {
72     return renderbuffer_->cleared();
73   }
74
75   virtual void SetCleared(
76       RenderbufferManager* renderbuffer_manager,
77       TextureManager* /* texture_manager */,
78       bool cleared) OVERRIDE {
79     renderbuffer_manager->SetCleared(renderbuffer_.get(), cleared);
80   }
81
82   virtual bool IsTexture(
83       TextureRef* /* texture */) const OVERRIDE {
84     return false;
85   }
86
87   virtual bool IsRenderbuffer(
88        Renderbuffer* renderbuffer) const OVERRIDE {
89     return renderbuffer_.get() == renderbuffer;
90   }
91
92   virtual bool CanRenderTo() const OVERRIDE {
93     return true;
94   }
95
96   virtual void DetachFromFramebuffer(Framebuffer* framebuffer) const OVERRIDE {
97     // Nothing to do for renderbuffers.
98   }
99
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;
106   }
107
108   Renderbuffer* renderbuffer() const {
109     return renderbuffer_.get();
110   }
111
112   virtual void AddToSignature(
113       TextureManager* texture_manager, std::string* signature) const OVERRIDE {
114     DCHECK(signature);
115     renderbuffer_->AddToSignature(signature);
116   }
117
118  protected:
119   virtual ~RenderbufferAttachment() { }
120
121  private:
122   scoped_refptr<Renderbuffer> renderbuffer_;
123
124   DISALLOW_COPY_AND_ASSIGN(RenderbufferAttachment);
125 };
126
127 class TextureAttachment
128     : public Framebuffer::Attachment {
129  public:
130   TextureAttachment(
131       TextureRef* texture_ref, GLenum target, GLint level, GLsizei samples)
132       : texture_ref_(texture_ref),
133         target_(target),
134         level_(level),
135         samples_(samples) {
136   }
137
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);
143     return temp_width;
144   }
145
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);
151     return temp_height;
152   }
153
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;
160   }
161
162   virtual GLsizei samples() const OVERRIDE {
163     return samples_;
164   }
165
166   virtual GLuint object_name() const OVERRIDE {
167     return texture_ref_->client_id();
168   }
169
170   virtual bool cleared() const OVERRIDE {
171     return texture_ref_->texture()->IsLevelCleared(target_, level_);
172   }
173
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);
180   }
181
182   virtual bool IsTexture(TextureRef* texture) const OVERRIDE {
183     return texture == texture_ref_.get();
184   }
185
186   virtual bool IsRenderbuffer(
187        Renderbuffer* /* renderbuffer */)
188           const OVERRIDE {
189     return false;
190   }
191
192   TextureRef* texture() const {
193     return texture_ref_.get();
194   }
195
196   virtual bool CanRenderTo() const OVERRIDE {
197     return texture_ref_->texture()->CanRenderTo();
198   }
199
200   virtual void DetachFromFramebuffer(Framebuffer* framebuffer)
201       const OVERRIDE {
202     texture_ref_->texture()->DetachFromFramebuffer();
203     framebuffer->OnTextureRefDetached(texture_ref_.get());
204   }
205
206   virtual bool ValidForAttachmentType(
207       GLenum attachment_type, uint32 max_color_attachments) OVERRIDE {
208     GLenum type = 0;
209     GLenum internal_format = 0;
210     if (!texture_ref_->texture()->GetLevelType(
211         target_, level_, &type, &internal_format)) {
212       return false;
213     }
214     uint32 need = GLES2Util::GetChannelsNeededForAttachmentType(
215         attachment_type, max_color_attachments);
216     uint32 have = GLES2Util::GetChannelsForFormat(internal_format);
217
218     // Workaround for NVIDIA drivers that incorrectly expose these formats as
219     // renderable:
220     if (internal_format == GL_LUMINANCE || internal_format == GL_ALPHA ||
221         internal_format == GL_LUMINANCE_ALPHA) {
222       return false;
223     }
224     return (need & have) != 0;
225   }
226
227   virtual void AddToSignature(
228       TextureManager* texture_manager, std::string* signature) const OVERRIDE {
229     DCHECK(signature);
230     texture_manager->AddToSignature(
231         texture_ref_.get(), target_, level_, signature);
232   }
233
234  protected:
235   virtual ~TextureAttachment() {}
236
237  private:
238   scoped_refptr<TextureRef> texture_ref_;
239   GLenum target_;
240   GLint level_;
241   GLsizei samples_;
242
243   DISALLOW_COPY_AND_ASSIGN(TextureAttachment);
244 };
245
246 FramebufferManager::TextureDetachObserver::TextureDetachObserver() {}
247
248 FramebufferManager::TextureDetachObserver::~TextureDetachObserver() {}
249
250 FramebufferManager::FramebufferManager(
251     uint32 max_draw_buffers, uint32 max_color_attachments)
252     : framebuffer_state_change_count_(1),
253       framebuffer_count_(0),
254       have_context_(true),
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);
259 }
260
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);
266 }
267
268 void Framebuffer::MarkAsDeleted() {
269   deleted_ = true;
270   while (!attachments_.empty()) {
271     Attachment* attachment = attachments_.begin()->second.get();
272     attachment->DetachFromFramebuffer(this);
273     attachments_.erase(attachments_.begin());
274   }
275 }
276
277 void FramebufferManager::Destroy(bool have_context) {
278   have_context_ = have_context;
279   framebuffers_.clear();
280 }
281
282 void FramebufferManager::StartTracking(
283     Framebuffer* /* framebuffer */) {
284   ++framebuffer_count_;
285 }
286
287 void FramebufferManager::StopTracking(
288     Framebuffer* /* framebuffer */) {
289   --framebuffer_count_;
290 }
291
292 void FramebufferManager::CreateFramebuffer(
293     GLuint client_id, GLuint service_id) {
294   std::pair<FramebufferMap::iterator, bool> result =
295       framebuffers_.insert(
296           std::make_pair(
297               client_id,
298               scoped_refptr<Framebuffer>(
299                   new Framebuffer(this, service_id))));
300   DCHECK(result.second);
301 }
302
303 Framebuffer::Framebuffer(
304     FramebufferManager* manager, GLuint service_id)
305     : manager_(manager),
306       deleted_(false),
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;
316 }
317
318 Framebuffer::~Framebuffer() {
319   if (manager_) {
320     if (manager_->have_context_) {
321       GLuint id = service_id();
322       glDeleteFramebuffersEXT(1, &id);
323     }
324     manager_->StopTracking(this);
325     manager_ = NULL;
326   }
327 }
328
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();
336   }
337   return false;
338 }
339
340 void Framebuffer::MarkAttachmentAsCleared(
341       RenderbufferManager* renderbuffer_manager,
342       TextureManager* texture_manager,
343       GLenum attachment,
344       bool cleared) {
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,
350                     texture_manager,
351                     cleared);
352     }
353   }
354 }
355
356 void Framebuffer::MarkAttachmentsAsCleared(
357       RenderbufferManager* renderbuffer_manager,
358       TextureManager* texture_manager,
359       bool cleared) {
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);
365     }
366   }
367 }
368
369 bool Framebuffer::HasDepthAttachment() const {
370   return attachments_.find(GL_DEPTH_STENCIL_ATTACHMENT) != attachments_.end() ||
371          attachments_.find(GL_DEPTH_ATTACHMENT) != attachments_.end();
372 }
373
374 bool Framebuffer::HasStencilAttachment() const {
375   return attachments_.find(GL_DEPTH_STENCIL_ATTACHMENT) != attachments_.end() ||
376          attachments_.find(GL_STENCIL_ATTACHMENT) != attachments_.end();
377 }
378
379 GLenum Framebuffer::GetColorAttachmentFormat() const {
380   AttachmentMap::const_iterator it = attachments_.find(GL_COLOR_ATTACHMENT0);
381   if (it == attachments_.end()) {
382     return 0;
383   }
384   const Attachment* attachment = it->second.get();
385   return attachment->internal_format();
386 }
387
388 GLenum Framebuffer::IsPossiblyComplete() const {
389   if (attachments_.empty()) {
390     return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
391   }
392
393   GLsizei width = -1;
394   GLsizei height = -1;
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;
402     }
403     if (width < 0) {
404       width = attachment->width();
405       height = attachment->height();
406       if (width == 0 || height == 0) {
407         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
408       }
409     } else {
410       if (attachment->width() != width || attachment->height() != height) {
411         return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
412       }
413     }
414
415     if (!attachment->CanRenderTo()) {
416       return GL_FRAMEBUFFER_UNSUPPORTED;
417     }
418   }
419
420   // This does not mean the framebuffer is actually complete. It just means our
421   // checks passed.
422   return GL_FRAMEBUFFER_COMPLETE;
423 }
424
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();
434       signature +=
435           base::StringPrintf("|Attachment|attachmentpoint=%04x", it->first);
436       attachment->AddToSignature(texture_manager, &signature);
437     }
438
439     if (!framebuffer_combo_complete_map_) {
440       framebuffer_combo_complete_map_ = new FramebufferComboCompleteMap();
441     }
442
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;
447     }
448   }
449
450   GLenum result = glCheckFramebufferStatusEXT(target);
451
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));
456   }
457
458   return result;
459 }
460
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()) {
467       return false;
468     }
469   }
470   return true;
471 }
472
473 GLenum Framebuffer::GetDrawBuffer(GLenum draw_buffer) const {
474   GLsizei index = static_cast<GLsizei>(
475       draw_buffer - GL_DRAW_BUFFER0_ARB);
476   CHECK(index >= 0 &&
477         index < static_cast<GLsizei>(manager_->max_draw_buffers_));
478   return draw_buffers_[index];
479 }
480
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];
485 }
486
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]);
491       if (!attachment)
492         continue;
493       if ((GLES2Util::GetChannelsForFormat(
494                attachment->internal_format()) & 0x0008) != 0)
495         return true;
496     }
497   }
498   return false;
499 }
500
501 void Framebuffer::UnbindRenderbuffer(
502     GLenum target, Renderbuffer* renderbuffer) {
503   bool done;
504   do {
505     done = true;
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);
513         done = false;
514         break;
515       }
516     }
517   } while (!done);
518 }
519
520 void Framebuffer::UnbindTexture(
521     GLenum target, TextureRef* texture_ref) {
522   bool done;
523   do {
524     done = true;
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);
532         done = false;
533         break;
534       }
535     }
536   } while (!done);
537 }
538
539 Framebuffer* FramebufferManager::GetFramebuffer(
540     GLuint client_id) {
541   FramebufferMap::iterator it = framebuffers_.find(client_id);
542   return it != framebuffers_.end() ? it->second.get() : NULL;
543 }
544
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);
550   }
551 }
552
553 void Framebuffer::AttachRenderbuffer(
554     GLenum attachment, Renderbuffer* renderbuffer) {
555   const Attachment* a = GetAttachment(attachment);
556   if (a)
557     a->DetachFromFramebuffer(this);
558   if (renderbuffer) {
559     attachments_[attachment] = scoped_refptr<Attachment>(
560         new RenderbufferAttachment(renderbuffer));
561   } else {
562     attachments_.erase(attachment);
563   }
564   framebuffer_complete_state_count_id_ = 0;
565 }
566
567 void Framebuffer::AttachTexture(
568     GLenum attachment, TextureRef* texture_ref, GLenum target,
569     GLint level, GLsizei samples) {
570   const Attachment* a = GetAttachment(attachment);
571   if (a)
572     a->DetachFromFramebuffer(this);
573   if (texture_ref) {
574     attachments_[attachment] = scoped_refptr<Attachment>(
575         new TextureAttachment(texture_ref, target, level, samples));
576     texture_ref->texture()->AttachToFramebuffer();
577   } else {
578     attachments_.erase(attachment);
579   }
580   framebuffer_complete_state_count_id_ = 0;
581 }
582
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();
589   }
590   return NULL;
591 }
592
593 void Framebuffer::OnTextureRefDetached(TextureRef* texture) {
594   manager_->OnTextureRefDetached(texture);
595 }
596
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;
604       return true;
605     }
606   }
607   return false;
608 }
609
610 void FramebufferManager::MarkAttachmentsAsCleared(
611     Framebuffer* framebuffer,
612     RenderbufferManager* renderbuffer_manager,
613     TextureManager* texture_manager) {
614   DCHECK(framebuffer);
615   framebuffer->MarkAttachmentsAsCleared(renderbuffer_manager,
616                                         texture_manager,
617                                         true);
618   MarkAsComplete(framebuffer);
619 }
620
621 void FramebufferManager::MarkAsComplete(
622     Framebuffer* framebuffer) {
623   DCHECK(framebuffer);
624   framebuffer->MarkAsComplete(framebuffer_state_change_count_);
625 }
626
627 bool FramebufferManager::IsComplete(
628     Framebuffer* framebuffer) {
629   DCHECK(framebuffer);
630   return framebuffer->framebuffer_complete_state_count_id() ==
631       framebuffer_state_change_count_;
632 }
633
634 void FramebufferManager::OnTextureRefDetached(TextureRef* texture) {
635   for (TextureDetachObserverVector::iterator it =
636            texture_detach_observers_.begin();
637        it != texture_detach_observers_.end();
638        ++it) {
639     TextureDetachObserver* observer = *it;
640     observer->OnTextureRefDetachedFromFramebuffer(texture);
641   }
642 }
643
644 }  // namespace gles2
645 }  // namespace gpu
646
647