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