gpu: Change Produce/ConsumeTexture to allow texture sharing
[chromium-blink-merge.git] / gpu / command_buffer / service / framebuffer_manager.cc
blobce08830463fefe1c8e3cb6de5e1eef96323d504c
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"
13 namespace gpu {
14 namespace gles2 {
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;
24 #else
25 bool Framebuffer::allow_framebuffer_combo_complete_map_ = true;
26 #endif
28 void Framebuffer::ClearFramebufferCompleteComboMap() {
29 if (framebuffer_combo_complete_map_) {
30 framebuffer_combo_complete_map_->clear();
34 class RenderbufferAttachment
35 : public Framebuffer::Attachment {
36 public:
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 {
75 return false;
78 virtual bool IsRenderbuffer(
79 Renderbuffer* renderbuffer) const OVERRIDE {
80 return renderbuffer_ == renderbuffer;
83 virtual bool CanRenderTo() const OVERRIDE {
84 return true;
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 {
105 DCHECK(signature);
106 renderbuffer_->AddToSignature(signature);
109 protected:
110 virtual ~RenderbufferAttachment() { }
112 private:
113 scoped_refptr<Renderbuffer> renderbuffer_;
115 DISALLOW_COPY_AND_ASSIGN(RenderbufferAttachment);
118 class TextureAttachment
119 : public Framebuffer::Attachment {
120 public:
121 TextureAttachment(
122 TextureRef* texture_ref, GLenum target, GLint level)
123 : texture_ref_(texture_ref),
124 target_(target),
125 level_(level) {
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);
133 return temp_width;
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);
141 return 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 {
153 return 0;
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 */)
177 const OVERRIDE {
178 return false;
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 {
195 GLenum type = 0;
196 GLenum internal_format = 0;
197 if (!texture_ref_->texture()->GetLevelType(
198 target_, level_, &type, &internal_format)) {
199 return false;
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 {
209 DCHECK(signature);
210 texture_manager->AddToSignature(texture_ref_, target_, level_, signature);
213 protected:
214 virtual ~TextureAttachment() {}
216 private:
217 scoped_refptr<TextureRef> texture_ref_;
218 GLenum target_;
219 GLint level_;
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),
228 have_context_(true),
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() {
243 deleted_ = true;
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(
270 std::make_pair(
271 client_id,
272 scoped_refptr<Framebuffer>(
273 new Framebuffer(this, service_id))));
274 DCHECK(result.second);
277 Framebuffer::Framebuffer(
278 FramebufferManager* manager, GLuint service_id)
279 : manager_(manager),
280 deleted_(false),
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() {
293 if (manager_) {
294 if (manager_->have_context_) {
295 GLuint id = service_id();
296 glDeleteFramebuffersEXT(1, &id);
298 manager_->StopTracking(this);
299 manager_ = NULL;
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();
311 return false;
314 void Framebuffer::MarkAttachmentAsCleared(
315 RenderbufferManager* renderbuffer_manager,
316 TextureManager* texture_manager,
317 GLenum attachment,
318 bool cleared) {
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,
324 texture_manager,
325 cleared);
330 void Framebuffer::MarkAttachmentsAsCleared(
331 RenderbufferManager* renderbuffer_manager,
332 TextureManager* texture_manager,
333 bool cleared) {
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()) {
356 return 0;
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;
367 GLsizei width = -1;
368 GLsizei height = -1;
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;
377 if (width < 0) {
378 width = attachment->width();
379 height = attachment->height();
380 if (width == 0 || height == 0) {
381 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
383 } else {
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
395 // checks passed.
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));
432 return result;
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()) {
441 return false;
444 return true;
447 GLenum Framebuffer::GetDrawBuffer(GLenum draw_buffer) const {
448 GLsizei index = static_cast<GLsizei>(
449 draw_buffer - GL_DRAW_BUFFER0_ARB);
450 CHECK(index >= 0 &&
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) {
463 bool done;
464 do {
465 done = true;
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);
473 done = false;
474 break;
477 } while (!done);
480 void Framebuffer::UnbindTexture(
481 GLenum target, TextureRef* texture_ref) {
482 bool done;
483 do {
484 done = true;
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);
492 done = false;
493 break;
496 } while (!done);
499 Framebuffer* FramebufferManager::GetFramebuffer(
500 GLuint client_id) {
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);
516 if (a)
517 a->DetachFromFramebuffer();
518 if (renderbuffer) {
519 attachments_[attachment] = scoped_refptr<Attachment>(
520 new RenderbufferAttachment(renderbuffer));
521 } else {
522 attachments_.erase(attachment);
524 framebuffer_complete_state_count_id_ = 0;
527 void Framebuffer::AttachTexture(
528 GLenum attachment, TextureRef* texture_ref, GLenum target,
529 GLint level) {
530 const Attachment* a = GetAttachment(attachment);
531 if (a)
532 a->DetachFromFramebuffer();
533 if (texture_ref) {
534 attachments_[attachment] = scoped_refptr<Attachment>(
535 new TextureAttachment(texture_ref, target, level));
536 texture_ref->texture()->AttachToFramebuffer();
537 } else {
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()) {
548 return it->second;
550 return NULL;
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;
560 return true;
563 return false;
566 void FramebufferManager::MarkAttachmentsAsCleared(
567 Framebuffer* framebuffer,
568 RenderbufferManager* renderbuffer_manager,
569 TextureManager* texture_manager) {
570 DCHECK(framebuffer);
571 framebuffer->MarkAttachmentsAsCleared(renderbuffer_manager,
572 texture_manager,
573 true);
574 MarkAsComplete(framebuffer);
577 void FramebufferManager::MarkAsComplete(
578 Framebuffer* framebuffer) {
579 DCHECK(framebuffer);
580 framebuffer->MarkAsComplete(framebuffer_state_change_count_);
583 bool FramebufferManager::IsComplete(
584 Framebuffer* framebuffer) {
585 DCHECK(framebuffer);
586 return framebuffer->framebuffer_complete_state_count_id() ==
587 framebuffer_state_change_count_;
590 } // namespace gles2
591 } // namespace gpu