OLD | NEW |
| (Empty) |
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 "sky/engine/config.h" | |
27 | |
28 #include "sky/engine/core/html/canvas/WebGLFramebuffer.h" | |
29 | |
30 #include "sky/engine/core/html/canvas/WebGLRenderingContextBase.h" | |
31 #include "sky/engine/platform/NotImplemented.h" | |
32 #include "sky/engine/wtf/Vector.h" | |
33 | |
34 namespace blink { | |
35 | |
36 namespace { | |
37 | |
38 Platform3DObject objectOrZero(WebGLObject* object) | |
39 { | |
40 return object ? object->object() : 0; | |
41 } | |
42 | |
43 class WebGLRenderbufferAttachment final : public WebGLFramebuffer::WebGLAtta
chment { | |
44 public: | |
45 static PassRefPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLRenderb
uffer*); | |
46 | |
47 private: | |
48 explicit WebGLRenderbufferAttachment(WebGLRenderbuffer*); | |
49 WebGLRenderbufferAttachment() { } | |
50 | |
51 virtual GLsizei width() const override; | |
52 virtual GLsizei height() const override; | |
53 virtual GLenum format() const override; | |
54 virtual GLenum type() const override; | |
55 virtual WebGLSharedObject* object() const override; | |
56 virtual bool isSharedObject(WebGLSharedObject*) const override; | |
57 virtual bool valid() const override; | |
58 virtual void onDetached(blink::WebGraphicsContext3D*) override; | |
59 virtual void attach(blink::WebGraphicsContext3D*, GLenum attachment) ove
rride; | |
60 virtual void unattach(blink::WebGraphicsContext3D*, GLenum attachment) o
verride; | |
61 | |
62 RefPtr<WebGLRenderbuffer> m_renderbuffer; | |
63 }; | |
64 | |
65 PassRefPtr<WebGLFramebuffer::WebGLAttachment> WebGLRenderbufferAttachment::c
reate(WebGLRenderbuffer* renderbuffer) | |
66 { | |
67 return adoptRef(new WebGLRenderbufferAttachment(renderbuffer)); | |
68 } | |
69 | |
70 WebGLRenderbufferAttachment::WebGLRenderbufferAttachment(WebGLRenderbuffer*
renderbuffer) | |
71 : m_renderbuffer(renderbuffer) | |
72 { | |
73 } | |
74 | |
75 GLsizei WebGLRenderbufferAttachment::width() const | |
76 { | |
77 return m_renderbuffer->width(); | |
78 } | |
79 | |
80 GLsizei WebGLRenderbufferAttachment::height() const | |
81 { | |
82 return m_renderbuffer->height(); | |
83 } | |
84 | |
85 GLenum WebGLRenderbufferAttachment::format() const | |
86 { | |
87 GLenum format = m_renderbuffer->internalFormat(); | |
88 if (format == GL_DEPTH_STENCIL_OES | |
89 && m_renderbuffer->emulatedStencilBuffer() | |
90 && m_renderbuffer->emulatedStencilBuffer()->internalFormat() != GL_S
TENCIL_INDEX8) { | |
91 return 0; | |
92 } | |
93 return format; | |
94 } | |
95 | |
96 WebGLSharedObject* WebGLRenderbufferAttachment::object() const | |
97 { | |
98 return m_renderbuffer->object() ? m_renderbuffer.get() : 0; | |
99 } | |
100 | |
101 bool WebGLRenderbufferAttachment::isSharedObject(WebGLSharedObject* object)
const | |
102 { | |
103 return object == m_renderbuffer; | |
104 } | |
105 | |
106 bool WebGLRenderbufferAttachment::valid() const | |
107 { | |
108 return m_renderbuffer->object(); | |
109 } | |
110 | |
111 void WebGLRenderbufferAttachment::onDetached(blink::WebGraphicsContext3D* co
ntext) | |
112 { | |
113 m_renderbuffer->onDetached(context); | |
114 } | |
115 | |
116 void WebGLRenderbufferAttachment::attach(blink::WebGraphicsContext3D* contex
t, GLenum attachment) | |
117 { | |
118 Platform3DObject object = objectOrZero(m_renderbuffer.get()); | |
119 if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL && m_renderbuffer-
>emulatedStencilBuffer()) { | |
120 context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT
, GL_RENDERBUFFER, object); | |
121 context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHME
NT, GL_RENDERBUFFER, objectOrZero(m_renderbuffer->emulatedStencilBuffer())); | |
122 } else { | |
123 context->framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_REND
ERBUFFER, object); | |
124 } | |
125 } | |
126 | |
127 void WebGLRenderbufferAttachment::unattach(blink::WebGraphicsContext3D* cont
ext, GLenum attachment) | |
128 { | |
129 if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) { | |
130 context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT
, GL_RENDERBUFFER, 0); | |
131 context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHME
NT, GL_RENDERBUFFER, 0); | |
132 } else { | |
133 context->framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_REND
ERBUFFER, 0); | |
134 } | |
135 } | |
136 | |
137 GLenum WebGLRenderbufferAttachment::type() const | |
138 { | |
139 notImplemented(); | |
140 return 0; | |
141 } | |
142 | |
143 class WebGLTextureAttachment final : public WebGLFramebuffer::WebGLAttachmen
t { | |
144 public: | |
145 static PassRefPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLTexture
*, GLenum target, GLint level); | |
146 | |
147 private: | |
148 WebGLTextureAttachment(WebGLTexture*, GLenum target, GLint level); | |
149 WebGLTextureAttachment() { } | |
150 | |
151 virtual GLsizei width() const override; | |
152 virtual GLsizei height() const override; | |
153 virtual GLenum format() const override; | |
154 virtual GLenum type() const override; | |
155 virtual WebGLSharedObject* object() const override; | |
156 virtual bool isSharedObject(WebGLSharedObject*) const override; | |
157 virtual bool valid() const override; | |
158 virtual void onDetached(blink::WebGraphicsContext3D*) override; | |
159 virtual void attach(blink::WebGraphicsContext3D*, GLenum attachment) ove
rride; | |
160 virtual void unattach(blink::WebGraphicsContext3D*, GLenum attachment) o
verride; | |
161 | |
162 RefPtr<WebGLTexture> m_texture; | |
163 GLenum m_target; | |
164 GLint m_level; | |
165 }; | |
166 | |
167 PassRefPtr<WebGLFramebuffer::WebGLAttachment> WebGLTextureAttachment::create
(WebGLTexture* texture, GLenum target, GLint level) | |
168 { | |
169 return adoptRef(new WebGLTextureAttachment(texture, target, level)); | |
170 } | |
171 | |
172 WebGLTextureAttachment::WebGLTextureAttachment(WebGLTexture* texture, GLenum
target, GLint level) | |
173 : m_texture(texture) | |
174 , m_target(target) | |
175 , m_level(level) | |
176 { | |
177 } | |
178 | |
179 GLsizei WebGLTextureAttachment::width() const | |
180 { | |
181 return m_texture->getWidth(m_target, m_level); | |
182 } | |
183 | |
184 GLsizei WebGLTextureAttachment::height() const | |
185 { | |
186 return m_texture->getHeight(m_target, m_level); | |
187 } | |
188 | |
189 GLenum WebGLTextureAttachment::format() const | |
190 { | |
191 return m_texture->getInternalFormat(m_target, m_level); | |
192 } | |
193 | |
194 WebGLSharedObject* WebGLTextureAttachment::object() const | |
195 { | |
196 return m_texture->object() ? m_texture.get() : 0; | |
197 } | |
198 | |
199 bool WebGLTextureAttachment::isSharedObject(WebGLSharedObject* object) const | |
200 { | |
201 return object == m_texture; | |
202 } | |
203 | |
204 bool WebGLTextureAttachment::valid() const | |
205 { | |
206 return m_texture->object(); | |
207 } | |
208 | |
209 void WebGLTextureAttachment::onDetached(blink::WebGraphicsContext3D* context
) | |
210 { | |
211 m_texture->onDetached(context); | |
212 } | |
213 | |
214 void WebGLTextureAttachment::attach(blink::WebGraphicsContext3D* context, GL
enum attachment) | |
215 { | |
216 Platform3DObject object = objectOrZero(m_texture.get()); | |
217 context->framebufferTexture2D(GL_FRAMEBUFFER, attachment, m_target, obje
ct, m_level); | |
218 } | |
219 | |
220 void WebGLTextureAttachment::unattach(blink::WebGraphicsContext3D* context,
GLenum attachment) | |
221 { | |
222 if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) { | |
223 context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m
_target, 0, m_level); | |
224 context->framebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
m_target, 0, m_level); | |
225 } else { | |
226 context->framebufferTexture2D(GL_FRAMEBUFFER, attachment, m_target,
0, m_level); | |
227 } | |
228 } | |
229 | |
230 GLenum WebGLTextureAttachment::type() const | |
231 { | |
232 return m_texture->getType(m_target, m_level); | |
233 } | |
234 | |
235 bool isColorRenderable(GLenum internalformat) | |
236 { | |
237 switch (internalformat) { | |
238 case GL_RGBA4: | |
239 case GL_RGB5_A1: | |
240 case GL_RGB565: | |
241 return true; | |
242 default: | |
243 return false; | |
244 } | |
245 } | |
246 | |
247 } // anonymous namespace | |
248 | |
249 WebGLFramebuffer::WebGLAttachment::WebGLAttachment() | |
250 { | |
251 } | |
252 | |
253 WebGLFramebuffer::WebGLAttachment::~WebGLAttachment() | |
254 { | |
255 } | |
256 | |
257 PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContextBase*
ctx) | |
258 { | |
259 return adoptRef(new WebGLFramebuffer(ctx)); | |
260 } | |
261 | |
262 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContextBase* ctx) | |
263 : WebGLContextObject(ctx) | |
264 , m_hasEverBeenBound(false) | |
265 { | |
266 setObject(ctx->webContext()->createFramebuffer()); | |
267 } | |
268 | |
269 WebGLFramebuffer::~WebGLFramebuffer() | |
270 { | |
271 // Delete the platform framebuffer resource. Explicit detachment | |
272 // is for the benefit of Oilpan, where the framebuffer object | |
273 // isn't detached when it and the WebGLRenderingContextBase object | |
274 // it is registered with are both finalized. Without Oilpan, the | |
275 // object will have been detached. | |
276 // | |
277 // To keep the code regular, the trivial detach()ment is always | |
278 // performed. | |
279 detachAndDeleteObject(); | |
280 } | |
281 | |
282 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum attachment, GLenu
m texTarget, WebGLTexture* texture, GLint level) | |
283 { | |
284 ASSERT(isBound()); | |
285 removeAttachmentFromBoundFramebuffer(attachment); | |
286 if (!object()) | |
287 return; | |
288 if (texture && texture->object()) { | |
289 m_attachments.add(attachment, WebGLTextureAttachment::create(texture, te
xTarget, level)); | |
290 drawBuffersIfNecessary(false); | |
291 texture->onAttached(); | |
292 } | |
293 } | |
294 | |
295 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum attachment, WebGL
Renderbuffer* renderbuffer) | |
296 { | |
297 ASSERT(isBound()); | |
298 removeAttachmentFromBoundFramebuffer(attachment); | |
299 if (!object()) | |
300 return; | |
301 if (renderbuffer && renderbuffer->object()) { | |
302 m_attachments.add(attachment, WebGLRenderbufferAttachment::create(render
buffer)); | |
303 drawBuffersIfNecessary(false); | |
304 renderbuffer->onAttached(); | |
305 } | |
306 } | |
307 | |
308 void WebGLFramebuffer::attach(GLenum attachment, GLenum attachmentPoint) | |
309 { | |
310 ASSERT(isBound()); | |
311 WebGLAttachment* attachmentObject = getAttachment(attachment); | |
312 if (attachmentObject) | |
313 attachmentObject->attach(context()->webContext(), attachmentPoint); | |
314 } | |
315 | |
316 WebGLSharedObject* WebGLFramebuffer::getAttachmentObject(GLenum attachment) cons
t | |
317 { | |
318 if (!object()) | |
319 return 0; | |
320 WebGLAttachment* attachmentObject = getAttachment(attachment); | |
321 return attachmentObject ? attachmentObject->object() : 0; | |
322 } | |
323 | |
324 bool WebGLFramebuffer::isAttachmentComplete(WebGLAttachment* attachedObject, GLe
num attachment, const char** reason) const | |
325 { | |
326 ASSERT(attachedObject && attachedObject->valid()); | |
327 ASSERT(reason); | |
328 | |
329 GLenum internalformat = attachedObject->format(); | |
330 WebGLSharedObject* object = attachedObject->object(); | |
331 ASSERT(object && (object->isTexture() || object->isRenderbuffer())); | |
332 | |
333 if (attachment == GL_DEPTH_ATTACHMENT) { | |
334 if (object->isRenderbuffer()) { | |
335 if (internalformat != GL_DEPTH_COMPONENT16) { | |
336 *reason = "the internalformat of the attached renderbuffer is no
t DEPTH_COMPONENT16"; | |
337 return false; | |
338 } | |
339 } else if (object->isTexture()) { | |
340 GLenum type = attachedObject->type(); | |
341 if (!(context()->extensionEnabled(WebGLDepthTextureName) && internal
format == GL_DEPTH_COMPONENT | |
342 && (type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT))) { | |
343 *reason = "the attached texture is not a depth texture"; | |
344 return false; | |
345 } | |
346 } | |
347 } else if (attachment == GL_STENCIL_ATTACHMENT) { | |
348 // Depend on the underlying GL drivers to check stencil textures | |
349 // and check renderbuffer type here only. | |
350 if (object->isRenderbuffer()) { | |
351 if (internalformat != GL_STENCIL_INDEX8) { | |
352 *reason = "the internalformat of the attached renderbuffer is no
t STENCIL_INDEX8"; | |
353 return false; | |
354 } | |
355 } | |
356 } else if (attachment == GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL) { | |
357 if (object->isRenderbuffer()) { | |
358 if (internalformat != GL_DEPTH_STENCIL_OES) { | |
359 *reason = "the internalformat of the attached renderbuffer is no
t DEPTH_STENCIL"; | |
360 return false; | |
361 } | |
362 } else if (object->isTexture()) { | |
363 GLenum type = attachedObject->type(); | |
364 if (!(context()->extensionEnabled(WebGLDepthTextureName) && internal
format == GL_DEPTH_STENCIL_OES | |
365 && type == GL_UNSIGNED_INT_24_8_OES)) { | |
366 *reason = "the attached texture is not a DEPTH_STENCIL texture"; | |
367 return false; | |
368 } | |
369 } | |
370 } else if (attachment == GL_COLOR_ATTACHMENT0 | |
371 || (context()->extensionEnabled(WebGLDrawBuffersName) && attachment > GL
_COLOR_ATTACHMENT0 | |
372 && attachment < static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + context()
->maxColorAttachments()))) { | |
373 if (object->isRenderbuffer()) { | |
374 if (!isColorRenderable(internalformat)) { | |
375 *reason = "the internalformat of the attached renderbuffer is no
t color-renderable"; | |
376 return false; | |
377 } | |
378 } else if (object->isTexture()) { | |
379 GLenum type = attachedObject->type(); | |
380 if (internalformat != GL_RGBA && internalformat != GL_RGB) { | |
381 *reason = "the internalformat of the attached texture is not col
or-renderable"; | |
382 return false; | |
383 } | |
384 // TODO: WEBGL_color_buffer_float and EXT_color_buffer_half_float ex
tensions have not been implemented in | |
385 // WebGL yet. It would be better to depend on the underlying GL driv
ers to check on rendering to floating point textures | |
386 // and add the check back to WebGL when above two extensions are imp
lemented. | |
387 // Assume UNSIGNED_BYTE is renderable here without the need to expli
citly check if GL_OES_rgb8_rgba8 extension is supported. | |
388 if (type != GL_UNSIGNED_BYTE | |
389 && type != GL_UNSIGNED_SHORT_5_6_5 | |
390 && type != GL_UNSIGNED_SHORT_4_4_4_4 | |
391 && type != GL_UNSIGNED_SHORT_5_5_5_1 | |
392 && !(type == GL_FLOAT && context()->extensionEnabled(OESTextureF
loatName)) | |
393 && !(type == GL_HALF_FLOAT_OES && context()->extensionEnabled(OE
STextureHalfFloatName))) { | |
394 *reason = "unsupported type: The attached texture is not support
ed to be rendered to"; | |
395 return false; | |
396 } | |
397 } | |
398 } else { | |
399 *reason = "unknown framebuffer attachment point"; | |
400 return false; | |
401 } | |
402 | |
403 if (!attachedObject->width() || !attachedObject->height()) { | |
404 *reason = "attachment has a 0 dimension"; | |
405 return false; | |
406 } | |
407 return true; | |
408 } | |
409 | |
410 WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment(GLenum attach
ment) const | |
411 { | |
412 const AttachmentMap::const_iterator it = m_attachments.find(attachment); | |
413 return (it != m_attachments.end()) ? it->value.get() : 0; | |
414 } | |
415 | |
416 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GLenum attachment) | |
417 { | |
418 ASSERT(isBound()); | |
419 if (!object()) | |
420 return; | |
421 | |
422 WebGLAttachment* attachmentObject = getAttachment(attachment); | |
423 if (attachmentObject) { | |
424 attachmentObject->onDetached(context()->webContext()); | |
425 m_attachments.remove(attachment); | |
426 drawBuffersIfNecessary(false); | |
427 switch (attachment) { | |
428 case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL: | |
429 attach(GL_DEPTH_ATTACHMENT, GL_DEPTH_ATTACHMENT); | |
430 attach(GL_STENCIL_ATTACHMENT, GL_STENCIL_ATTACHMENT); | |
431 break; | |
432 case GL_DEPTH_ATTACHMENT: | |
433 attach(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL, GL_DEPTH_ATTACHMENT); | |
434 break; | |
435 case GL_STENCIL_ATTACHMENT: | |
436 attach(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL, GL_STENCIL_ATTACHMENT); | |
437 break; | |
438 } | |
439 } | |
440 } | |
441 | |
442 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(WebGLSharedObject* a
ttachment) | |
443 { | |
444 ASSERT(isBound()); | |
445 if (!object()) | |
446 return; | |
447 if (!attachment) | |
448 return; | |
449 | |
450 bool checkMore = true; | |
451 while (checkMore) { | |
452 checkMore = false; | |
453 for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachm
ents.end(); ++it) { | |
454 WebGLAttachment* attachmentObject = it->value.get(); | |
455 if (attachmentObject->isSharedObject(attachment)) { | |
456 GLenum attachmentType = it->key; | |
457 attachmentObject->unattach(context()->webContext(), attachmentTy
pe); | |
458 removeAttachmentFromBoundFramebuffer(attachmentType); | |
459 checkMore = true; | |
460 break; | |
461 } | |
462 } | |
463 } | |
464 } | |
465 | |
466 GLenum WebGLFramebuffer::colorBufferFormat() const | |
467 { | |
468 if (!object()) | |
469 return 0; | |
470 WebGLAttachment* attachment = getAttachment(GL_COLOR_ATTACHMENT0); | |
471 if (!attachment) | |
472 return 0; | |
473 return attachment->format(); | |
474 } | |
475 | |
476 GLenum WebGLFramebuffer::checkStatus(const char** reason) const | |
477 { | |
478 unsigned count = 0; | |
479 GLsizei width = 0, height = 0; | |
480 bool haveDepth = false; | |
481 bool haveStencil = false; | |
482 bool haveDepthStencil = false; | |
483 for (AttachmentMap::const_iterator it = m_attachments.begin(); it != m_attac
hments.end(); ++it) { | |
484 WebGLAttachment* attachment = it->value.get(); | |
485 if (!isAttachmentComplete(attachment, it->key, reason)) | |
486 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; | |
487 if (!attachment->valid()) { | |
488 *reason = "attachment is not valid"; | |
489 return GL_FRAMEBUFFER_UNSUPPORTED; | |
490 } | |
491 if (!attachment->format()) { | |
492 *reason = "attachment is an unsupported format"; | |
493 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; | |
494 } | |
495 switch (it->key) { | |
496 case GL_DEPTH_ATTACHMENT: | |
497 haveDepth = true; | |
498 break; | |
499 case GL_STENCIL_ATTACHMENT: | |
500 haveStencil = true; | |
501 break; | |
502 case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL: | |
503 haveDepthStencil = true; | |
504 break; | |
505 } | |
506 if (!count) { | |
507 width = attachment->width(); | |
508 height = attachment->height(); | |
509 } else { | |
510 if (width != attachment->width() || height != attachment->height())
{ | |
511 *reason = "attachments do not have the same dimensions"; | |
512 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; | |
513 } | |
514 } | |
515 ++count; | |
516 } | |
517 if (!count) { | |
518 *reason = "no attachments"; | |
519 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; | |
520 } | |
521 if (!width || !height) { | |
522 *reason = "framebuffer has a 0 dimension"; | |
523 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; | |
524 } | |
525 // WebGL specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments. | |
526 if ((haveDepthStencil && (haveDepth || haveStencil)) || (haveDepth && haveSt
encil)) { | |
527 *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments"; | |
528 return GL_FRAMEBUFFER_UNSUPPORTED; | |
529 } | |
530 return GL_FRAMEBUFFER_COMPLETE; | |
531 } | |
532 | |
533 bool WebGLFramebuffer::onAccess(blink::WebGraphicsContext3D* context3d, const ch
ar** reason) | |
534 { | |
535 if (checkStatus(reason) != GL_FRAMEBUFFER_COMPLETE) | |
536 return false; | |
537 return true; | |
538 } | |
539 | |
540 bool WebGLFramebuffer::hasStencilBuffer() const | |
541 { | |
542 WebGLAttachment* attachment = getAttachment(GL_STENCIL_ATTACHMENT); | |
543 if (!attachment) | |
544 attachment = getAttachment(GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL); | |
545 return attachment && attachment->valid(); | |
546 } | |
547 | |
548 void WebGLFramebuffer::deleteObjectImpl(blink::WebGraphicsContext3D* context3d,
Platform3DObject object) | |
549 { | |
550 #if !ENABLE(OILPAN) | |
551 // With Oilpan, both the AttachmentMap and its WebGLAttachment objects are | |
552 // GCed objects and cannot be accessed, as they may have been finalized | |
553 // already during the same GC sweep. | |
554 // | |
555 // The WebGLAttachment-derived classes instead handle detachment | |
556 // on their own when finalizing, so the explicit notification is | |
557 // not needed. | |
558 for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments
.end(); ++it) | |
559 it->value->onDetached(context3d); | |
560 #endif | |
561 | |
562 context3d->deleteFramebuffer(object); | |
563 } | |
564 | |
565 bool WebGLFramebuffer::isBound() const | |
566 { | |
567 return (context()->m_framebufferBinding.get() == this); | |
568 } | |
569 | |
570 void WebGLFramebuffer::drawBuffers(const Vector<GLenum>& bufs) | |
571 { | |
572 m_drawBuffers = bufs; | |
573 m_filteredDrawBuffers.resize(m_drawBuffers.size()); | |
574 for (size_t i = 0; i < m_filteredDrawBuffers.size(); ++i) | |
575 m_filteredDrawBuffers[i] = GL_NONE; | |
576 drawBuffersIfNecessary(true); | |
577 } | |
578 | |
579 void WebGLFramebuffer::drawBuffersIfNecessary(bool force) | |
580 { | |
581 if (!context()->extensionEnabled(WebGLDrawBuffersName)) | |
582 return; | |
583 bool reset = force; | |
584 // This filtering works around graphics driver bugs on Mac OS X. | |
585 for (size_t i = 0; i < m_drawBuffers.size(); ++i) { | |
586 if (m_drawBuffers[i] != GL_NONE && getAttachment(m_drawBuffers[i])) { | |
587 if (m_filteredDrawBuffers[i] != m_drawBuffers[i]) { | |
588 m_filteredDrawBuffers[i] = m_drawBuffers[i]; | |
589 reset = true; | |
590 } | |
591 } else { | |
592 if (m_filteredDrawBuffers[i] != GL_NONE) { | |
593 m_filteredDrawBuffers[i] = GL_NONE; | |
594 reset = true; | |
595 } | |
596 } | |
597 } | |
598 if (reset) { | |
599 context()->webContext()->drawBuffersEXT( | |
600 m_filteredDrawBuffers.size(), m_filteredDrawBuffers.data()); | |
601 } | |
602 } | |
603 | |
604 GLenum WebGLFramebuffer::getDrawBuffer(GLenum drawBuffer) | |
605 { | |
606 int index = static_cast<int>(drawBuffer - GL_DRAW_BUFFER0_EXT); | |
607 ASSERT(index >= 0); | |
608 if (index < static_cast<int>(m_drawBuffers.size())) | |
609 return m_drawBuffers[index]; | |
610 if (drawBuffer == GL_DRAW_BUFFER0_EXT) | |
611 return GL_COLOR_ATTACHMENT0; | |
612 return GL_NONE; | |
613 } | |
614 | |
615 } | |
OLD | NEW |