• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 
28 #include "core/html/canvas/WebGLFramebuffer.h"
29 
30 #include "core/html/canvas/WebGLRenderingContextBase.h"
31 #include "platform/NotImplemented.h"
32 
33 namespace blink {
34 
35 namespace {
36 
objectOrZero(WebGLObject * object)37     Platform3DObject objectOrZero(WebGLObject* object)
38     {
39         return object ? object->object() : 0;
40     }
41 
42     class WebGLRenderbufferAttachment FINAL : public WebGLFramebuffer::WebGLAttachment {
43     public:
44         static PassRefPtrWillBeRawPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLRenderbuffer*);
45 
46         virtual void trace(Visitor*) OVERRIDE;
47 
48     private:
49         explicit WebGLRenderbufferAttachment(WebGLRenderbuffer*);
WebGLRenderbufferAttachment()50         WebGLRenderbufferAttachment() { }
51 
52         virtual GLsizei width() const OVERRIDE;
53         virtual GLsizei height() const OVERRIDE;
54         virtual GLenum format() const OVERRIDE;
55         virtual GLenum type() const OVERRIDE;
56         virtual WebGLSharedObject* object() const OVERRIDE;
57         virtual bool isSharedObject(WebGLSharedObject*) const OVERRIDE;
58         virtual bool valid() const OVERRIDE;
59         virtual void onDetached(blink::WebGraphicsContext3D*) OVERRIDE;
60         virtual void attach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE;
61         virtual void unattach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE;
62 
63         RefPtrWillBeMember<WebGLRenderbuffer> m_renderbuffer;
64     };
65 
create(WebGLRenderbuffer * renderbuffer)66     PassRefPtrWillBeRawPtr<WebGLFramebuffer::WebGLAttachment> WebGLRenderbufferAttachment::create(WebGLRenderbuffer* renderbuffer)
67     {
68         return adoptRefWillBeNoop(new WebGLRenderbufferAttachment(renderbuffer));
69     }
70 
trace(Visitor * visitor)71     void WebGLRenderbufferAttachment::trace(Visitor* visitor)
72     {
73         visitor->trace(m_renderbuffer);
74         WebGLFramebuffer::WebGLAttachment::trace(visitor);
75     }
76 
WebGLRenderbufferAttachment(WebGLRenderbuffer * renderbuffer)77     WebGLRenderbufferAttachment::WebGLRenderbufferAttachment(WebGLRenderbuffer* renderbuffer)
78         : m_renderbuffer(renderbuffer)
79     {
80     }
81 
width() const82     GLsizei WebGLRenderbufferAttachment::width() const
83     {
84         return m_renderbuffer->width();
85     }
86 
height() const87     GLsizei WebGLRenderbufferAttachment::height() const
88     {
89         return m_renderbuffer->height();
90     }
91 
format() const92     GLenum WebGLRenderbufferAttachment::format() const
93     {
94         GLenum format = m_renderbuffer->internalFormat();
95         if (format == GL_DEPTH_STENCIL_OES
96             && m_renderbuffer->emulatedStencilBuffer()
97             && m_renderbuffer->emulatedStencilBuffer()->internalFormat() != GL_STENCIL_INDEX8) {
98             return 0;
99         }
100         return format;
101     }
102 
object() const103     WebGLSharedObject* WebGLRenderbufferAttachment::object() const
104     {
105         return m_renderbuffer->object() ? m_renderbuffer.get() : 0;
106     }
107 
isSharedObject(WebGLSharedObject * object) const108     bool WebGLRenderbufferAttachment::isSharedObject(WebGLSharedObject* object) const
109     {
110         return object == m_renderbuffer;
111     }
112 
valid() const113     bool WebGLRenderbufferAttachment::valid() const
114     {
115         return m_renderbuffer->object();
116     }
117 
onDetached(blink::WebGraphicsContext3D * context)118     void WebGLRenderbufferAttachment::onDetached(blink::WebGraphicsContext3D* context)
119     {
120         m_renderbuffer->onDetached(context);
121     }
122 
attach(blink::WebGraphicsContext3D * context,GLenum attachment)123     void WebGLRenderbufferAttachment::attach(blink::WebGraphicsContext3D* context, GLenum attachment)
124     {
125         Platform3DObject object = objectOrZero(m_renderbuffer.get());
126         if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL && m_renderbuffer->emulatedStencilBuffer()) {
127             context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, object);
128             context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, objectOrZero(m_renderbuffer->emulatedStencilBuffer()));
129         } else {
130             context->framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, object);
131         }
132     }
133 
unattach(blink::WebGraphicsContext3D * context,GLenum attachment)134     void WebGLRenderbufferAttachment::unattach(blink::WebGraphicsContext3D* context, GLenum attachment)
135     {
136         if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) {
137             context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
138             context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
139         } else {
140             context->framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, 0);
141         }
142     }
143 
type() const144     GLenum WebGLRenderbufferAttachment::type() const
145     {
146         notImplemented();
147         return 0;
148     }
149 
150     class WebGLTextureAttachment FINAL : public WebGLFramebuffer::WebGLAttachment {
151     public:
152         static PassRefPtrWillBeRawPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLTexture*, GLenum target, GLint level);
153 
154         virtual void trace(Visitor*) OVERRIDE;
155 
156     private:
157         WebGLTextureAttachment(WebGLTexture*, GLenum target, GLint level);
WebGLTextureAttachment()158         WebGLTextureAttachment() { }
159 
160         virtual GLsizei width() const OVERRIDE;
161         virtual GLsizei height() const OVERRIDE;
162         virtual GLenum format() const OVERRIDE;
163         virtual GLenum type() const OVERRIDE;
164         virtual WebGLSharedObject* object() const OVERRIDE;
165         virtual bool isSharedObject(WebGLSharedObject*) const OVERRIDE;
166         virtual bool valid() const OVERRIDE;
167         virtual void onDetached(blink::WebGraphicsContext3D*) OVERRIDE;
168         virtual void attach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE;
169         virtual void unattach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE;
170 
171         RefPtrWillBeMember<WebGLTexture> m_texture;
172         GLenum m_target;
173         GLint m_level;
174     };
175 
create(WebGLTexture * texture,GLenum target,GLint level)176     PassRefPtrWillBeRawPtr<WebGLFramebuffer::WebGLAttachment> WebGLTextureAttachment::create(WebGLTexture* texture, GLenum target, GLint level)
177     {
178         return adoptRefWillBeNoop(new WebGLTextureAttachment(texture, target, level));
179     }
180 
trace(Visitor * visitor)181     void WebGLTextureAttachment::trace(Visitor* visitor)
182     {
183         visitor->trace(m_texture);
184         WebGLFramebuffer::WebGLAttachment::trace(visitor);
185     }
186 
WebGLTextureAttachment(WebGLTexture * texture,GLenum target,GLint level)187     WebGLTextureAttachment::WebGLTextureAttachment(WebGLTexture* texture, GLenum target, GLint level)
188         : m_texture(texture)
189         , m_target(target)
190         , m_level(level)
191     {
192     }
193 
width() const194     GLsizei WebGLTextureAttachment::width() const
195     {
196         return m_texture->getWidth(m_target, m_level);
197     }
198 
height() const199     GLsizei WebGLTextureAttachment::height() const
200     {
201         return m_texture->getHeight(m_target, m_level);
202     }
203 
format() const204     GLenum WebGLTextureAttachment::format() const
205     {
206         return m_texture->getInternalFormat(m_target, m_level);
207     }
208 
object() const209     WebGLSharedObject* WebGLTextureAttachment::object() const
210     {
211         return m_texture->object() ? m_texture.get() : 0;
212     }
213 
isSharedObject(WebGLSharedObject * object) const214     bool WebGLTextureAttachment::isSharedObject(WebGLSharedObject* object) const
215     {
216         return object == m_texture;
217     }
218 
valid() const219     bool WebGLTextureAttachment::valid() const
220     {
221         return m_texture->object();
222     }
223 
onDetached(blink::WebGraphicsContext3D * context)224     void WebGLTextureAttachment::onDetached(blink::WebGraphicsContext3D* context)
225     {
226         m_texture->onDetached(context);
227     }
228 
attach(blink::WebGraphicsContext3D * context,GLenum attachment)229     void WebGLTextureAttachment::attach(blink::WebGraphicsContext3D* context, GLenum attachment)
230     {
231         Platform3DObject object = objectOrZero(m_texture.get());
232         context->framebufferTexture2D(GL_FRAMEBUFFER, attachment, m_target, object, m_level);
233     }
234 
unattach(blink::WebGraphicsContext3D * context,GLenum attachment)235     void WebGLTextureAttachment::unattach(blink::WebGraphicsContext3D* context, GLenum attachment)
236     {
237         if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) {
238             context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_target, 0, m_level);
239             context->framebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, m_target, 0, m_level);
240         } else {
241             context->framebufferTexture2D(GL_FRAMEBUFFER, attachment, m_target, 0, m_level);
242         }
243     }
244 
type() const245     GLenum WebGLTextureAttachment::type() const
246     {
247         return m_texture->getType(m_target, m_level);
248     }
249 
isColorRenderable(GLenum internalformat)250     bool isColorRenderable(GLenum internalformat)
251     {
252         switch (internalformat) {
253         case GL_RGBA4:
254         case GL_RGB5_A1:
255         case GL_RGB565:
256             return true;
257         default:
258             return false;
259         }
260     }
261 
262 } // anonymous namespace
263 
WebGLAttachment()264 WebGLFramebuffer::WebGLAttachment::WebGLAttachment()
265 {
266 }
267 
~WebGLAttachment()268 WebGLFramebuffer::WebGLAttachment::~WebGLAttachment()
269 {
270 }
271 
create(WebGLRenderingContextBase * ctx)272 PassRefPtrWillBeRawPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContextBase* ctx)
273 {
274     return adoptRefWillBeNoop(new WebGLFramebuffer(ctx));
275 }
276 
WebGLFramebuffer(WebGLRenderingContextBase * ctx)277 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContextBase* ctx)
278     : WebGLContextObject(ctx)
279     , m_hasEverBeenBound(false)
280 {
281     setObject(ctx->webContext()->createFramebuffer());
282 }
283 
~WebGLFramebuffer()284 WebGLFramebuffer::~WebGLFramebuffer()
285 {
286     // Delete the platform framebuffer resource. Explicit detachment
287     // is for the benefit of Oilpan, where the framebuffer object
288     // isn't detached when it and the WebGLRenderingContextBase object
289     // it is registered with are both finalized. Without Oilpan, the
290     // object will have been detached.
291     //
292     // To keep the code regular, the trivial detach()ment is always
293     // performed.
294     detachAndDeleteObject();
295 }
296 
setAttachmentForBoundFramebuffer(GLenum attachment,GLenum texTarget,WebGLTexture * texture,GLint level)297 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum attachment, GLenum texTarget, WebGLTexture* texture, GLint level)
298 {
299     ASSERT(isBound());
300     removeAttachmentFromBoundFramebuffer(attachment);
301     if (!object())
302         return;
303     if (texture && texture->object()) {
304         m_attachments.add(attachment, WebGLTextureAttachment::create(texture, texTarget, level));
305         drawBuffersIfNecessary(false);
306         texture->onAttached();
307     }
308 }
309 
setAttachmentForBoundFramebuffer(GLenum attachment,WebGLRenderbuffer * renderbuffer)310 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum attachment, WebGLRenderbuffer* renderbuffer)
311 {
312     ASSERT(isBound());
313     removeAttachmentFromBoundFramebuffer(attachment);
314     if (!object())
315         return;
316     if (renderbuffer && renderbuffer->object()) {
317         m_attachments.add(attachment, WebGLRenderbufferAttachment::create(renderbuffer));
318         drawBuffersIfNecessary(false);
319         renderbuffer->onAttached();
320     }
321 }
322 
attach(GLenum attachment,GLenum attachmentPoint)323 void WebGLFramebuffer::attach(GLenum attachment, GLenum attachmentPoint)
324 {
325     ASSERT(isBound());
326     WebGLAttachment* attachmentObject = getAttachment(attachment);
327     if (attachmentObject)
328         attachmentObject->attach(context()->webContext(), attachmentPoint);
329 }
330 
getAttachmentObject(GLenum attachment) const331 WebGLSharedObject* WebGLFramebuffer::getAttachmentObject(GLenum attachment) const
332 {
333     if (!object())
334         return 0;
335     WebGLAttachment* attachmentObject = getAttachment(attachment);
336     return attachmentObject ? attachmentObject->object() : 0;
337 }
338 
isAttachmentComplete(WebGLAttachment * attachedObject,GLenum attachment,const char ** reason) const339 bool WebGLFramebuffer::isAttachmentComplete(WebGLAttachment* attachedObject, GLenum attachment, const char** reason) const
340 {
341     ASSERT(attachedObject && attachedObject->valid());
342     ASSERT(reason);
343 
344     GLenum internalformat = attachedObject->format();
345     WebGLSharedObject* object = attachedObject->object();
346     ASSERT(object && (object->isTexture() || object->isRenderbuffer()));
347 
348     if (attachment == GL_DEPTH_ATTACHMENT) {
349         if (object->isRenderbuffer()) {
350             if (internalformat != GL_DEPTH_COMPONENT16) {
351                 *reason = "the internalformat of the attached renderbuffer is not DEPTH_COMPONENT16";
352                 return false;
353             }
354         } else if (object->isTexture()) {
355             GLenum type = attachedObject->type();
356             if (!(context()->extensionEnabled(WebGLDepthTextureName) && internalformat == GL_DEPTH_COMPONENT
357                 && (type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT))) {
358                 *reason = "the attached texture is not a depth texture";
359                 return false;
360             }
361         }
362     } else if (attachment == GL_STENCIL_ATTACHMENT) {
363         // Depend on the underlying GL drivers to check stencil textures
364         // and check renderbuffer type here only.
365         if (object->isRenderbuffer()) {
366             if (internalformat != GL_STENCIL_INDEX8) {
367                 *reason = "the internalformat of the attached renderbuffer is not STENCIL_INDEX8";
368                 return false;
369             }
370         }
371     } else if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) {
372         if (object->isRenderbuffer()) {
373             if (internalformat != GL_DEPTH_STENCIL_OES) {
374                 *reason = "the internalformat of the attached renderbuffer is not DEPTH_STENCIL";
375                 return false;
376             }
377         } else if (object->isTexture()) {
378             GLenum type = attachedObject->type();
379             if (!(context()->extensionEnabled(WebGLDepthTextureName) && internalformat == GL_DEPTH_STENCIL_OES
380                 && type == GL_UNSIGNED_INT_24_8_OES)) {
381                 *reason = "the attached texture is not a DEPTH_STENCIL texture";
382                 return false;
383             }
384         }
385     } else if (attachment == GL_COLOR_ATTACHMENT0
386         || (context()->extensionEnabled(WebGLDrawBuffersName) && attachment > GL_COLOR_ATTACHMENT0
387             && attachment < static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + context()->maxColorAttachments()))) {
388         if (object->isRenderbuffer()) {
389             if (!isColorRenderable(internalformat)) {
390                 *reason = "the internalformat of the attached renderbuffer is not color-renderable";
391                 return false;
392             }
393         } else if (object->isTexture()) {
394             GLenum type = attachedObject->type();
395             if (internalformat != GL_RGBA && internalformat != GL_RGB) {
396                 *reason = "the internalformat of the attached texture is not color-renderable";
397                 return false;
398             }
399             // TODO: WEBGL_color_buffer_float and EXT_color_buffer_half_float extensions have not been implemented in
400             // WebGL yet. It would be better to depend on the underlying GL drivers to check on rendering to floating point textures
401             // and add the check back to WebGL when above two extensions are implemented.
402             // Assume UNSIGNED_BYTE is renderable here without the need to explicitly check if GL_OES_rgb8_rgba8 extension is supported.
403             if (type != GL_UNSIGNED_BYTE
404                 && type != GL_UNSIGNED_SHORT_5_6_5
405                 && type != GL_UNSIGNED_SHORT_4_4_4_4
406                 && type != GL_UNSIGNED_SHORT_5_5_5_1
407                 && !(type == GL_FLOAT && context()->extensionEnabled(OESTextureFloatName))
408                 && !(type == GL_HALF_FLOAT_OES && context()->extensionEnabled(OESTextureHalfFloatName))) {
409                 *reason = "unsupported type: The attached texture is not supported to be rendered to";
410                 return false;
411             }
412         }
413     } else {
414         *reason = "unknown framebuffer attachment point";
415         return false;
416     }
417 
418     if (!attachedObject->width() || !attachedObject->height()) {
419         *reason = "attachment has a 0 dimension";
420         return false;
421     }
422     return true;
423 }
424 
getAttachment(GLenum attachment) const425 WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment(GLenum attachment) const
426 {
427     const AttachmentMap::const_iterator it = m_attachments.find(attachment);
428     return (it != m_attachments.end()) ? it->value.get() : 0;
429 }
430 
removeAttachmentFromBoundFramebuffer(GLenum attachment)431 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GLenum attachment)
432 {
433     ASSERT(isBound());
434     if (!object())
435         return;
436 
437     WebGLAttachment* attachmentObject = getAttachment(attachment);
438     if (attachmentObject) {
439         attachmentObject->onDetached(context()->webContext());
440         m_attachments.remove(attachment);
441         drawBuffersIfNecessary(false);
442         switch (attachment) {
443         case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
444             attach(GL_DEPTH_ATTACHMENT, GL_DEPTH_ATTACHMENT);
445             attach(GL_STENCIL_ATTACHMENT, GL_STENCIL_ATTACHMENT);
446             break;
447         case GL_DEPTH_ATTACHMENT:
448             attach(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL, GL_DEPTH_ATTACHMENT);
449             break;
450         case GL_STENCIL_ATTACHMENT:
451             attach(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL, GL_STENCIL_ATTACHMENT);
452             break;
453         }
454     }
455 }
456 
removeAttachmentFromBoundFramebuffer(WebGLSharedObject * attachment)457 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(WebGLSharedObject* attachment)
458 {
459     ASSERT(isBound());
460     if (!object())
461         return;
462     if (!attachment)
463         return;
464 
465     bool checkMore = true;
466     while (checkMore) {
467         checkMore = false;
468         for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
469             WebGLAttachment* attachmentObject = it->value.get();
470             if (attachmentObject->isSharedObject(attachment)) {
471                 GLenum attachmentType = it->key;
472                 attachmentObject->unattach(context()->webContext(), attachmentType);
473                 removeAttachmentFromBoundFramebuffer(attachmentType);
474                 checkMore = true;
475                 break;
476             }
477         }
478     }
479 }
480 
colorBufferFormat() const481 GLenum WebGLFramebuffer::colorBufferFormat() const
482 {
483     if (!object())
484         return 0;
485     WebGLAttachment* attachment = getAttachment(GL_COLOR_ATTACHMENT0);
486     if (!attachment)
487         return 0;
488     return attachment->format();
489 }
490 
checkStatus(const char ** reason) const491 GLenum WebGLFramebuffer::checkStatus(const char** reason) const
492 {
493     unsigned count = 0;
494     GLsizei width = 0, height = 0;
495     bool haveDepth = false;
496     bool haveStencil = false;
497     bool haveDepthStencil = false;
498     for (AttachmentMap::const_iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
499         WebGLAttachment* attachment = it->value.get();
500         if (!isAttachmentComplete(attachment, it->key, reason))
501             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
502         if (!attachment->valid()) {
503             *reason = "attachment is not valid";
504             return GL_FRAMEBUFFER_UNSUPPORTED;
505         }
506         if (!attachment->format()) {
507             *reason = "attachment is an unsupported format";
508             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
509         }
510         switch (it->key) {
511         case GL_DEPTH_ATTACHMENT:
512             haveDepth = true;
513             break;
514         case GL_STENCIL_ATTACHMENT:
515             haveStencil = true;
516             break;
517         case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
518             haveDepthStencil = true;
519             break;
520         }
521         if (!count) {
522             width = attachment->width();
523             height = attachment->height();
524         } else {
525             if (width != attachment->width() || height != attachment->height()) {
526                 *reason = "attachments do not have the same dimensions";
527                 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
528             }
529         }
530         ++count;
531     }
532     if (!count) {
533         *reason = "no attachments";
534         return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
535     }
536     if (!width || !height) {
537         *reason = "framebuffer has a 0 dimension";
538         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
539     }
540     // WebGL specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments.
541     if ((haveDepthStencil && (haveDepth || haveStencil)) || (haveDepth && haveStencil)) {
542         *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments";
543         return GL_FRAMEBUFFER_UNSUPPORTED;
544     }
545     return GL_FRAMEBUFFER_COMPLETE;
546 }
547 
onAccess(blink::WebGraphicsContext3D * context3d,const char ** reason)548 bool WebGLFramebuffer::onAccess(blink::WebGraphicsContext3D* context3d, const char** reason)
549 {
550     if (checkStatus(reason) != GL_FRAMEBUFFER_COMPLETE)
551         return false;
552     return true;
553 }
554 
hasStencilBuffer() const555 bool WebGLFramebuffer::hasStencilBuffer() const
556 {
557     WebGLAttachment* attachment = getAttachment(GL_STENCIL_ATTACHMENT);
558     if (!attachment)
559         attachment = getAttachment(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL);
560     return attachment && attachment->valid();
561 }
562 
deleteObjectImpl(blink::WebGraphicsContext3D * context3d,Platform3DObject object)563 void WebGLFramebuffer::deleteObjectImpl(blink::WebGraphicsContext3D* context3d, Platform3DObject object)
564 {
565 #if !ENABLE(OILPAN)
566     // With Oilpan, both the AttachmentMap and its WebGLAttachment objects are
567     // GCed objects and cannot be accessed, as they may have been finalized
568     // already during the same GC sweep.
569     //
570     // The WebGLAttachment-derived classes instead handle detachment
571     // on their own when finalizing, so the explicit notification is
572     // not needed.
573     for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it)
574         it->value->onDetached(context3d);
575 #endif
576 
577     context3d->deleteFramebuffer(object);
578 }
579 
isBound() const580 bool WebGLFramebuffer::isBound() const
581 {
582     return (context()->m_framebufferBinding.get() == this);
583 }
584 
drawBuffers(const Vector<GLenum> & bufs)585 void WebGLFramebuffer::drawBuffers(const Vector<GLenum>& bufs)
586 {
587     m_drawBuffers = bufs;
588     m_filteredDrawBuffers.resize(m_drawBuffers.size());
589     for (size_t i = 0; i < m_filteredDrawBuffers.size(); ++i)
590         m_filteredDrawBuffers[i] = GL_NONE;
591     drawBuffersIfNecessary(true);
592 }
593 
drawBuffersIfNecessary(bool force)594 void WebGLFramebuffer::drawBuffersIfNecessary(bool force)
595 {
596     if (!context()->extensionEnabled(WebGLDrawBuffersName))
597         return;
598     bool reset = force;
599     // This filtering works around graphics driver bugs on Mac OS X.
600     for (size_t i = 0; i < m_drawBuffers.size(); ++i) {
601         if (m_drawBuffers[i] != GL_NONE && getAttachment(m_drawBuffers[i])) {
602             if (m_filteredDrawBuffers[i] != m_drawBuffers[i]) {
603                 m_filteredDrawBuffers[i] = m_drawBuffers[i];
604                 reset = true;
605             }
606         } else {
607             if (m_filteredDrawBuffers[i] != GL_NONE) {
608                 m_filteredDrawBuffers[i] = GL_NONE;
609                 reset = true;
610             }
611         }
612     }
613     if (reset) {
614         context()->webContext()->drawBuffersEXT(
615             m_filteredDrawBuffers.size(), m_filteredDrawBuffers.data());
616     }
617 }
618 
getDrawBuffer(GLenum drawBuffer)619 GLenum WebGLFramebuffer::getDrawBuffer(GLenum drawBuffer)
620 {
621     int index = static_cast<int>(drawBuffer - GL_DRAW_BUFFER0_EXT);
622     ASSERT(index >= 0);
623     if (index < static_cast<int>(m_drawBuffers.size()))
624         return m_drawBuffers[index];
625     if (drawBuffer == GL_DRAW_BUFFER0_EXT)
626         return GL_COLOR_ATTACHMENT0;
627     return GL_NONE;
628 }
629 
trace(Visitor * visitor)630 void WebGLFramebuffer::trace(Visitor* visitor)
631 {
632 #if ENABLE(OILPAN)
633     visitor->trace(m_attachments);
634 #endif
635     WebGLContextObject::trace(visitor);
636 }
637 
638 }
639