• 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 WebCore {
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 PassRefPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLRenderbuffer*);
45 
46     private:
47         WebGLRenderbufferAttachment(WebGLRenderbuffer*);
48         virtual GLsizei width() const OVERRIDE;
49         virtual GLsizei height() const OVERRIDE;
50         virtual GLenum format() const OVERRIDE;
51         virtual GLenum type() const OVERRIDE;
52         virtual WebGLSharedObject* object() const OVERRIDE;
53         virtual bool isSharedObject(WebGLSharedObject*) const OVERRIDE;
54         virtual bool valid() const OVERRIDE;
55         virtual void onDetached(blink::WebGraphicsContext3D*) OVERRIDE;
56         virtual void attach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE;
57         virtual void unattach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE;
58 
WebGLRenderbufferAttachment()59         WebGLRenderbufferAttachment() { };
60 
61         RefPtr<WebGLRenderbuffer> m_renderbuffer;
62     };
63 
create(WebGLRenderbuffer * renderbuffer)64     PassRefPtr<WebGLFramebuffer::WebGLAttachment> WebGLRenderbufferAttachment::create(WebGLRenderbuffer* renderbuffer)
65     {
66         return adoptRef(new WebGLRenderbufferAttachment(renderbuffer));
67     }
68 
WebGLRenderbufferAttachment(WebGLRenderbuffer * renderbuffer)69     WebGLRenderbufferAttachment::WebGLRenderbufferAttachment(WebGLRenderbuffer* renderbuffer)
70         : m_renderbuffer(renderbuffer)
71     {
72     }
73 
width() const74     GLsizei WebGLRenderbufferAttachment::width() const
75     {
76         return m_renderbuffer->width();
77     }
78 
height() const79     GLsizei WebGLRenderbufferAttachment::height() const
80     {
81         return m_renderbuffer->height();
82     }
83 
format() const84     GLenum WebGLRenderbufferAttachment::format() const
85     {
86         GLenum format = m_renderbuffer->internalFormat();
87         if (format == GL_DEPTH_STENCIL_OES
88             && m_renderbuffer->emulatedStencilBuffer()
89             && m_renderbuffer->emulatedStencilBuffer()->internalFormat() != GL_STENCIL_INDEX8) {
90             return 0;
91         }
92         return format;
93     }
94 
object() const95     WebGLSharedObject* WebGLRenderbufferAttachment::object() const
96     {
97         return m_renderbuffer->object() ? m_renderbuffer.get() : 0;
98     }
99 
isSharedObject(WebGLSharedObject * object) const100     bool WebGLRenderbufferAttachment::isSharedObject(WebGLSharedObject* object) const
101     {
102         return object == m_renderbuffer;
103     }
104 
valid() const105     bool WebGLRenderbufferAttachment::valid() const
106     {
107         return m_renderbuffer->object();
108     }
109 
onDetached(blink::WebGraphicsContext3D * context)110     void WebGLRenderbufferAttachment::onDetached(blink::WebGraphicsContext3D* context)
111     {
112         m_renderbuffer->onDetached(context);
113     }
114 
attach(blink::WebGraphicsContext3D * context,GLenum attachment)115     void WebGLRenderbufferAttachment::attach(blink::WebGraphicsContext3D* context, GLenum attachment)
116     {
117         Platform3DObject object = objectOrZero(m_renderbuffer.get());
118         if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL && m_renderbuffer->emulatedStencilBuffer()) {
119             context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, object);
120             context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, objectOrZero(m_renderbuffer->emulatedStencilBuffer()));
121         } else {
122             context->framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, object);
123         }
124     }
125 
unattach(blink::WebGraphicsContext3D * context,GLenum attachment)126     void WebGLRenderbufferAttachment::unattach(blink::WebGraphicsContext3D* context, GLenum attachment)
127     {
128         if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) {
129             context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
130             context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
131         } else {
132             context->framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, 0);
133         }
134     }
135 
type() const136     GLenum WebGLRenderbufferAttachment::type() const
137     {
138         notImplemented();
139         return 0;
140     }
141 
142     class WebGLTextureAttachment FINAL : public WebGLFramebuffer::WebGLAttachment {
143     public:
144         static PassRefPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLTexture*, GLenum target, GLint level);
145 
146     private:
147         WebGLTextureAttachment(WebGLTexture*, GLenum target, GLint level);
148         virtual GLsizei width() const OVERRIDE;
149         virtual GLsizei height() const OVERRIDE;
150         virtual GLenum format() const OVERRIDE;
151         virtual GLenum type() const OVERRIDE;
152         virtual WebGLSharedObject* object() const OVERRIDE;
153         virtual bool isSharedObject(WebGLSharedObject*) const OVERRIDE;
154         virtual bool valid() const OVERRIDE;
155         virtual void onDetached(blink::WebGraphicsContext3D*) OVERRIDE;
156         virtual void attach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE;
157         virtual void unattach(blink::WebGraphicsContext3D*, GLenum attachment) OVERRIDE;
158 
WebGLTextureAttachment()159         WebGLTextureAttachment() { };
160 
161         RefPtr<WebGLTexture> m_texture;
162         GLenum m_target;
163         GLint m_level;
164     };
165 
create(WebGLTexture * texture,GLenum target,GLint level)166     PassRefPtr<WebGLFramebuffer::WebGLAttachment> WebGLTextureAttachment::create(WebGLTexture* texture, GLenum target, GLint level)
167     {
168         return adoptRef(new WebGLTextureAttachment(texture, target, level));
169     }
170 
WebGLTextureAttachment(WebGLTexture * texture,GLenum target,GLint level)171     WebGLTextureAttachment::WebGLTextureAttachment(WebGLTexture* texture, GLenum target, GLint level)
172         : m_texture(texture)
173         , m_target(target)
174         , m_level(level)
175     {
176     }
177 
width() const178     GLsizei WebGLTextureAttachment::width() const
179     {
180         return m_texture->getWidth(m_target, m_level);
181     }
182 
height() const183     GLsizei WebGLTextureAttachment::height() const
184     {
185         return m_texture->getHeight(m_target, m_level);
186     }
187 
format() const188     GLenum WebGLTextureAttachment::format() const
189     {
190         return m_texture->getInternalFormat(m_target, m_level);
191     }
192 
object() const193     WebGLSharedObject* WebGLTextureAttachment::object() const
194     {
195         return m_texture->object() ? m_texture.get() : 0;
196     }
197 
isSharedObject(WebGLSharedObject * object) const198     bool WebGLTextureAttachment::isSharedObject(WebGLSharedObject* object) const
199     {
200         return object == m_texture;
201     }
202 
valid() const203     bool WebGLTextureAttachment::valid() const
204     {
205         return m_texture->object();
206     }
207 
onDetached(blink::WebGraphicsContext3D * context)208     void WebGLTextureAttachment::onDetached(blink::WebGraphicsContext3D* context)
209     {
210         m_texture->onDetached(context);
211     }
212 
attach(blink::WebGraphicsContext3D * context,GLenum attachment)213     void WebGLTextureAttachment::attach(blink::WebGraphicsContext3D* context, GLenum attachment)
214     {
215         Platform3DObject object = objectOrZero(m_texture.get());
216         context->framebufferTexture2D(GL_FRAMEBUFFER, attachment, m_target, object, m_level);
217     }
218 
unattach(blink::WebGraphicsContext3D * context,GLenum attachment)219     void WebGLTextureAttachment::unattach(blink::WebGraphicsContext3D* context, GLenum attachment)
220     {
221         if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) {
222             context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_target, 0, m_level);
223             context->framebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, m_target, 0, m_level);
224         } else {
225             context->framebufferTexture2D(GL_FRAMEBUFFER, attachment, m_target, 0, m_level);
226         }
227     }
228 
type() const229     GLenum WebGLTextureAttachment::type() const
230     {
231         return m_texture->getType(m_target, m_level);
232     }
233 
isColorRenderable(GLenum internalformat)234     bool isColorRenderable(GLenum internalformat)
235     {
236         switch (internalformat) {
237         case GL_RGBA4:
238         case GL_RGB5_A1:
239         case GL_RGB565:
240             return true;
241         default:
242             return false;
243         }
244     }
245 
246 } // anonymous namespace
247 
WebGLAttachment()248 WebGLFramebuffer::WebGLAttachment::WebGLAttachment()
249 {
250 }
251 
~WebGLAttachment()252 WebGLFramebuffer::WebGLAttachment::~WebGLAttachment()
253 {
254 }
255 
create(WebGLRenderingContextBase * ctx)256 PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContextBase* ctx)
257 {
258     return adoptRef(new WebGLFramebuffer(ctx));
259 }
260 
WebGLFramebuffer(WebGLRenderingContextBase * ctx)261 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContextBase* ctx)
262     : WebGLContextObject(ctx)
263     , m_hasEverBeenBound(false)
264 {
265     ScriptWrappable::init(this);
266     setObject(ctx->webContext()->createFramebuffer());
267 }
268 
~WebGLFramebuffer()269 WebGLFramebuffer::~WebGLFramebuffer()
270 {
271     deleteObject(0);
272 }
273 
setAttachmentForBoundFramebuffer(GLenum attachment,GLenum texTarget,WebGLTexture * texture,GLint level)274 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum attachment, GLenum texTarget, WebGLTexture* texture, GLint level)
275 {
276     ASSERT(isBound());
277     removeAttachmentFromBoundFramebuffer(attachment);
278     if (!object())
279         return;
280     if (texture && texture->object()) {
281         m_attachments.add(attachment, WebGLTextureAttachment::create(texture, texTarget, level));
282         drawBuffersIfNecessary(false);
283         texture->onAttached();
284     }
285 }
286 
setAttachmentForBoundFramebuffer(GLenum attachment,WebGLRenderbuffer * renderbuffer)287 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum attachment, WebGLRenderbuffer* renderbuffer)
288 {
289     ASSERT(isBound());
290     removeAttachmentFromBoundFramebuffer(attachment);
291     if (!object())
292         return;
293     if (renderbuffer && renderbuffer->object()) {
294         m_attachments.add(attachment, WebGLRenderbufferAttachment::create(renderbuffer));
295         drawBuffersIfNecessary(false);
296         renderbuffer->onAttached();
297     }
298 }
299 
attach(GLenum attachment,GLenum attachmentPoint)300 void WebGLFramebuffer::attach(GLenum attachment, GLenum attachmentPoint)
301 {
302     ASSERT(isBound());
303     WebGLAttachment* attachmentObject = getAttachment(attachment);
304     if (attachmentObject)
305         attachmentObject->attach(context()->webContext(), attachmentPoint);
306 }
307 
getAttachmentObject(GLenum attachment) const308 WebGLSharedObject* WebGLFramebuffer::getAttachmentObject(GLenum attachment) const
309 {
310     if (!object())
311         return 0;
312     WebGLAttachment* attachmentObject = getAttachment(attachment);
313     return attachmentObject ? attachmentObject->object() : 0;
314 }
315 
isAttachmentComplete(WebGLAttachment * attachedObject,GLenum attachment,const char ** reason) const316 bool WebGLFramebuffer::isAttachmentComplete(WebGLAttachment* attachedObject, GLenum attachment, const char** reason) const
317 {
318     ASSERT(attachedObject && attachedObject->valid());
319     ASSERT(reason);
320 
321     GLenum internalformat = attachedObject->format();
322     WebGLSharedObject* object = attachedObject->object();
323     ASSERT(object && (object->isTexture() || object->isRenderbuffer()));
324 
325     if (attachment == GL_DEPTH_ATTACHMENT) {
326         if (object->isRenderbuffer()) {
327             if (internalformat != GL_DEPTH_COMPONENT16) {
328                 *reason = "the internalformat of the attached renderbuffer is not DEPTH_COMPONENT16";
329                 return false;
330             }
331         } else if (object->isTexture()) {
332             GLenum type = attachedObject->type();
333             if (!(context()->extensionEnabled(WebGLDepthTextureName) && internalformat == GL_DEPTH_COMPONENT
334                 && (type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT))) {
335                 *reason = "the attached texture is not a depth texture";
336                 return false;
337             }
338         }
339     } else if (attachment == GL_STENCIL_ATTACHMENT) {
340         // Depend on the underlying GL drivers to check stencil textures
341         // and check renderbuffer type here only.
342         if (object->isRenderbuffer()) {
343             if (internalformat != GL_STENCIL_INDEX8) {
344                 *reason = "the internalformat of the attached renderbuffer is not STENCIL_INDEX8";
345                 return false;
346             }
347         }
348     } else if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) {
349         if (object->isRenderbuffer()) {
350             if (internalformat != GL_DEPTH_STENCIL_OES) {
351                 *reason = "the internalformat of the attached renderbuffer is not DEPTH_STENCIL";
352                 return false;
353             }
354         } else if (object->isTexture()) {
355             GLenum type = attachedObject->type();
356             if (!(context()->extensionEnabled(WebGLDepthTextureName) && internalformat == GL_DEPTH_STENCIL_OES
357                 && type == GL_UNSIGNED_INT_24_8_OES)) {
358                 *reason = "the attached texture is not a DEPTH_STENCIL texture";
359                 return false;
360             }
361         }
362     } else if (attachment == GL_COLOR_ATTACHMENT0
363         || (context()->extensionEnabled(WebGLDrawBuffersName) && attachment > GL_COLOR_ATTACHMENT0
364             && attachment < static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + context()->maxColorAttachments()))) {
365         if (object->isRenderbuffer()) {
366             if (!isColorRenderable(internalformat)) {
367                 *reason = "the internalformat of the attached renderbuffer is not color-renderable";
368                 return false;
369             }
370         } else if (object->isTexture()) {
371             GLenum type = attachedObject->type();
372             if (internalformat != GL_RGBA && internalformat != GL_RGB) {
373                 *reason = "the internalformat of the attached texture is not color-renderable";
374                 return false;
375             }
376             // TODO: WEBGL_color_buffer_float and EXT_color_buffer_half_float extensions have not been implemented in
377             // WebGL yet. It would be better to depend on the underlying GL drivers to check on rendering to floating point textures
378             // and add the check back to WebGL when above two extensions are implemented.
379             // Assume UNSIGNED_BYTE is renderable here without the need to explicitly check if GL_OES_rgb8_rgba8 extension is supported.
380             if (type != GL_UNSIGNED_BYTE
381                 && type != GL_UNSIGNED_SHORT_5_6_5
382                 && type != GL_UNSIGNED_SHORT_4_4_4_4
383                 && type != GL_UNSIGNED_SHORT_5_5_5_1
384                 && !(type == GL_FLOAT && context()->extensionEnabled(OESTextureFloatName))
385                 && !(type == GL_HALF_FLOAT_OES && context()->extensionEnabled(OESTextureHalfFloatName))) {
386                 *reason = "unsupported type: The attached texture is not supported to be rendered to";
387                 return false;
388             }
389         }
390     } else {
391         *reason = "unknown framebuffer attachment point";
392         return false;
393     }
394 
395     if (!attachedObject->width() || !attachedObject->height()) {
396         *reason = "attachment has a 0 dimension";
397         return false;
398     }
399     return true;
400 }
401 
getAttachment(GLenum attachment) const402 WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment(GLenum attachment) const
403 {
404     const AttachmentMap::const_iterator it = m_attachments.find(attachment);
405     return (it != m_attachments.end()) ? it->value.get() : 0;
406 }
407 
removeAttachmentFromBoundFramebuffer(GLenum attachment)408 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GLenum attachment)
409 {
410     ASSERT(isBound());
411     if (!object())
412         return;
413 
414     WebGLAttachment* attachmentObject = getAttachment(attachment);
415     if (attachmentObject) {
416         attachmentObject->onDetached(context()->webContext());
417         m_attachments.remove(attachment);
418         drawBuffersIfNecessary(false);
419         switch (attachment) {
420         case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
421             attach(GL_DEPTH_ATTACHMENT, GL_DEPTH_ATTACHMENT);
422             attach(GL_STENCIL_ATTACHMENT, GL_STENCIL_ATTACHMENT);
423             break;
424         case GL_DEPTH_ATTACHMENT:
425             attach(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL, GL_DEPTH_ATTACHMENT);
426             break;
427         case GL_STENCIL_ATTACHMENT:
428             attach(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL, GL_STENCIL_ATTACHMENT);
429             break;
430         }
431     }
432 }
433 
removeAttachmentFromBoundFramebuffer(WebGLSharedObject * attachment)434 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(WebGLSharedObject* attachment)
435 {
436     ASSERT(isBound());
437     if (!object())
438         return;
439     if (!attachment)
440         return;
441 
442     bool checkMore = true;
443     while (checkMore) {
444         checkMore = false;
445         for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
446             WebGLAttachment* attachmentObject = it->value.get();
447             if (attachmentObject->isSharedObject(attachment)) {
448                 GLenum attachmentType = it->key;
449                 attachmentObject->unattach(context()->webContext(), attachmentType);
450                 removeAttachmentFromBoundFramebuffer(attachmentType);
451                 checkMore = true;
452                 break;
453             }
454         }
455     }
456 }
457 
colorBufferFormat() const458 GLenum WebGLFramebuffer::colorBufferFormat() const
459 {
460     if (!object())
461         return 0;
462     WebGLAttachment* attachment = getAttachment(GL_COLOR_ATTACHMENT0);
463     if (!attachment)
464         return 0;
465     return attachment->format();
466 }
467 
checkStatus(const char ** reason) const468 GLenum WebGLFramebuffer::checkStatus(const char** reason) const
469 {
470     unsigned count = 0;
471     GLsizei width = 0, height = 0;
472     bool haveDepth = false;
473     bool haveStencil = false;
474     bool haveDepthStencil = false;
475     for (AttachmentMap::const_iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
476         WebGLAttachment* attachment = it->value.get();
477         if (!isAttachmentComplete(attachment, it->key, reason))
478             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
479         if (!attachment->valid()) {
480             *reason = "attachment is not valid";
481             return GL_FRAMEBUFFER_UNSUPPORTED;
482         }
483         if (!attachment->format()) {
484             *reason = "attachment is an unsupported format";
485             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
486         }
487         switch (it->key) {
488         case GL_DEPTH_ATTACHMENT:
489             haveDepth = true;
490             break;
491         case GL_STENCIL_ATTACHMENT:
492             haveStencil = true;
493             break;
494         case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
495             haveDepthStencil = true;
496             break;
497         }
498         if (!count) {
499             width = attachment->width();
500             height = attachment->height();
501         } else {
502             if (width != attachment->width() || height != attachment->height()) {
503                 *reason = "attachments do not have the same dimensions";
504                 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
505             }
506         }
507         ++count;
508     }
509     if (!count) {
510         *reason = "no attachments";
511         return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
512     }
513     if (!width || !height) {
514         *reason = "framebuffer has a 0 dimension";
515         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
516     }
517     // WebGL specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments.
518     if ((haveDepthStencil && (haveDepth || haveStencil)) || (haveDepth && haveStencil)) {
519         *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments";
520         return GL_FRAMEBUFFER_UNSUPPORTED;
521     }
522     return GL_FRAMEBUFFER_COMPLETE;
523 }
524 
onAccess(blink::WebGraphicsContext3D * context3d,const char ** reason)525 bool WebGLFramebuffer::onAccess(blink::WebGraphicsContext3D* context3d, const char** reason)
526 {
527     if (checkStatus(reason) != GL_FRAMEBUFFER_COMPLETE)
528         return false;
529     return true;
530 }
531 
hasStencilBuffer() const532 bool WebGLFramebuffer::hasStencilBuffer() const
533 {
534     WebGLAttachment* attachment = getAttachment(GL_STENCIL_ATTACHMENT);
535     if (!attachment)
536         attachment = getAttachment(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL);
537     return attachment && attachment->valid();
538 }
539 
deleteObjectImpl(blink::WebGraphicsContext3D * context3d,Platform3DObject object)540 void WebGLFramebuffer::deleteObjectImpl(blink::WebGraphicsContext3D* context3d, Platform3DObject object)
541 {
542     for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it)
543         it->value->onDetached(context3d);
544 
545     context3d->deleteFramebuffer(object);
546 }
547 
isBound() const548 bool WebGLFramebuffer::isBound() const
549 {
550     return (context()->m_framebufferBinding.get() == this);
551 }
552 
drawBuffers(const Vector<GLenum> & bufs)553 void WebGLFramebuffer::drawBuffers(const Vector<GLenum>& bufs)
554 {
555     m_drawBuffers = bufs;
556     m_filteredDrawBuffers.resize(m_drawBuffers.size());
557     for (size_t i = 0; i < m_filteredDrawBuffers.size(); ++i)
558         m_filteredDrawBuffers[i] = GL_NONE;
559     drawBuffersIfNecessary(true);
560 }
561 
drawBuffersIfNecessary(bool force)562 void WebGLFramebuffer::drawBuffersIfNecessary(bool force)
563 {
564     if (!context()->extensionEnabled(WebGLDrawBuffersName))
565         return;
566     bool reset = force;
567     // This filtering works around graphics driver bugs on Mac OS X.
568     for (size_t i = 0; i < m_drawBuffers.size(); ++i) {
569         if (m_drawBuffers[i] != GL_NONE && getAttachment(m_drawBuffers[i])) {
570             if (m_filteredDrawBuffers[i] != m_drawBuffers[i]) {
571                 m_filteredDrawBuffers[i] = m_drawBuffers[i];
572                 reset = true;
573             }
574         } else {
575             if (m_filteredDrawBuffers[i] != GL_NONE) {
576                 m_filteredDrawBuffers[i] = GL_NONE;
577                 reset = true;
578             }
579         }
580     }
581     if (reset) {
582         context()->webContext()->drawBuffersEXT(
583             m_filteredDrawBuffers.size(), m_filteredDrawBuffers.data());
584     }
585 }
586 
getDrawBuffer(GLenum drawBuffer)587 GLenum WebGLFramebuffer::getDrawBuffer(GLenum drawBuffer)
588 {
589     int index = static_cast<int>(drawBuffer - GL_DRAW_BUFFER0_EXT);
590     ASSERT(index >= 0);
591     if (index < static_cast<int>(m_drawBuffers.size()))
592         return m_drawBuffers[index];
593     if (drawBuffer == GL_DRAW_BUFFER0_EXT)
594         return GL_COLOR_ATTACHMENT0;
595     return GL_NONE;
596 }
597 
598 }
599