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