1 | /* |
2 | * Copyright (C) 2009-2017 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 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 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 | #include "WebGLFramebuffer.h" |
28 | |
29 | #if ENABLE(WEBGL) |
30 | |
31 | #include "Extensions3D.h" |
32 | #include "WebGLContextGroup.h" |
33 | #include "WebGLDrawBuffers.h" |
34 | #include "WebGLRenderingContextBase.h" |
35 | |
36 | namespace WebCore { |
37 | |
38 | namespace { |
39 | |
40 | Platform3DObject objectOrZero(WebGLObject* object) |
41 | { |
42 | return object ? object->object() : 0; |
43 | } |
44 | |
45 | class WebGLRenderbufferAttachment : public WebGLFramebuffer::WebGLAttachment { |
46 | public: |
47 | static Ref<WebGLFramebuffer::WebGLAttachment> create(WebGLRenderbuffer*); |
48 | |
49 | private: |
50 | WebGLRenderbufferAttachment(WebGLRenderbuffer*); |
51 | GC3Dsizei getWidth() const override; |
52 | GC3Dsizei getHeight() const override; |
53 | GC3Denum getFormat() const override; |
54 | WebGLSharedObject* getObject() const override; |
55 | bool isSharedObject(WebGLSharedObject*) const override; |
56 | bool isValid() const override; |
57 | bool isInitialized() const override; |
58 | void setInitialized() override; |
59 | void onDetached(GraphicsContext3D*) override; |
60 | void attach(GraphicsContext3D*, GC3Denum attachment) override; |
61 | void unattach(GraphicsContext3D*, GC3Denum attachment) override; |
62 | |
63 | WebGLRenderbufferAttachment() { }; |
64 | |
65 | RefPtr<WebGLRenderbuffer> m_renderbuffer; |
66 | }; |
67 | |
68 | Ref<WebGLFramebuffer::WebGLAttachment> WebGLRenderbufferAttachment::create(WebGLRenderbuffer* renderbuffer) |
69 | { |
70 | return adoptRef(*new WebGLRenderbufferAttachment(renderbuffer)); |
71 | } |
72 | |
73 | WebGLRenderbufferAttachment::WebGLRenderbufferAttachment(WebGLRenderbuffer* renderbuffer) |
74 | : m_renderbuffer(renderbuffer) |
75 | { |
76 | } |
77 | |
78 | GC3Dsizei WebGLRenderbufferAttachment::getWidth() const |
79 | { |
80 | return m_renderbuffer->getWidth(); |
81 | } |
82 | |
83 | GC3Dsizei WebGLRenderbufferAttachment::getHeight() const |
84 | { |
85 | return m_renderbuffer->getHeight(); |
86 | } |
87 | |
88 | GC3Denum WebGLRenderbufferAttachment::getFormat() const |
89 | { |
90 | return m_renderbuffer->getInternalFormat(); |
91 | } |
92 | |
93 | WebGLSharedObject* WebGLRenderbufferAttachment::getObject() const |
94 | { |
95 | return m_renderbuffer->object() ? m_renderbuffer.get() : 0; |
96 | } |
97 | |
98 | bool WebGLRenderbufferAttachment::isSharedObject(WebGLSharedObject* object) const |
99 | { |
100 | return object == m_renderbuffer; |
101 | } |
102 | |
103 | bool WebGLRenderbufferAttachment::isValid() const |
104 | { |
105 | return m_renderbuffer->object(); |
106 | } |
107 | |
108 | bool WebGLRenderbufferAttachment::isInitialized() const |
109 | { |
110 | return m_renderbuffer->object() && m_renderbuffer->isInitialized(); |
111 | } |
112 | |
113 | void WebGLRenderbufferAttachment::setInitialized() |
114 | { |
115 | if (m_renderbuffer->object()) |
116 | m_renderbuffer->setInitialized(); |
117 | } |
118 | |
119 | void WebGLRenderbufferAttachment::onDetached(GraphicsContext3D* context) |
120 | { |
121 | m_renderbuffer->onDetached(context); |
122 | } |
123 | |
124 | void WebGLRenderbufferAttachment::attach(GraphicsContext3D* context, GC3Denum attachment) |
125 | { |
126 | Platform3DObject object = objectOrZero(m_renderbuffer.get()); |
127 | context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, attachment, GraphicsContext3D::RENDERBUFFER, object); |
128 | } |
129 | |
130 | void WebGLRenderbufferAttachment::unattach(GraphicsContext3D* context, GC3Denum attachment) |
131 | { |
132 | if (attachment == GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT) { |
133 | context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, 0); |
134 | context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, 0); |
135 | } else |
136 | context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, attachment, GraphicsContext3D::RENDERBUFFER, 0); |
137 | } |
138 | |
139 | class WebGLTextureAttachment : public WebGLFramebuffer::WebGLAttachment { |
140 | public: |
141 | static Ref<WebGLFramebuffer::WebGLAttachment> create(WebGLTexture*, GC3Denum target, GC3Dint level); |
142 | |
143 | private: |
144 | WebGLTextureAttachment(WebGLTexture*, GC3Denum target, GC3Dint level); |
145 | GC3Dsizei getWidth() const override; |
146 | GC3Dsizei getHeight() const override; |
147 | GC3Denum getFormat() const override; |
148 | WebGLSharedObject* getObject() const override; |
149 | bool isSharedObject(WebGLSharedObject*) const override; |
150 | bool isValid() const override; |
151 | bool isInitialized() const override; |
152 | void setInitialized() override; |
153 | void onDetached(GraphicsContext3D*) override; |
154 | void attach(GraphicsContext3D*, GC3Denum attachment) override; |
155 | void unattach(GraphicsContext3D*, GC3Denum attachment) override; |
156 | |
157 | WebGLTextureAttachment() { }; |
158 | |
159 | RefPtr<WebGLTexture> m_texture; |
160 | GC3Denum m_target; |
161 | GC3Dint m_level; |
162 | }; |
163 | |
164 | Ref<WebGLFramebuffer::WebGLAttachment> WebGLTextureAttachment::create(WebGLTexture* texture, GC3Denum target, GC3Dint level) |
165 | { |
166 | return adoptRef(*new WebGLTextureAttachment(texture, target, level)); |
167 | } |
168 | |
169 | WebGLTextureAttachment::WebGLTextureAttachment(WebGLTexture* texture, GC3Denum target, GC3Dint level) |
170 | : m_texture(texture) |
171 | , m_target(target) |
172 | , m_level(level) |
173 | { |
174 | } |
175 | |
176 | GC3Dsizei WebGLTextureAttachment::getWidth() const |
177 | { |
178 | return m_texture->getWidth(m_target, m_level); |
179 | } |
180 | |
181 | GC3Dsizei WebGLTextureAttachment::getHeight() const |
182 | { |
183 | return m_texture->getHeight(m_target, m_level); |
184 | } |
185 | |
186 | GC3Denum WebGLTextureAttachment::getFormat() const |
187 | { |
188 | return m_texture->getInternalFormat(m_target, m_level); |
189 | } |
190 | |
191 | WebGLSharedObject* WebGLTextureAttachment::getObject() const |
192 | { |
193 | return m_texture->object() ? m_texture.get() : 0; |
194 | } |
195 | |
196 | bool WebGLTextureAttachment::isSharedObject(WebGLSharedObject* object) const |
197 | { |
198 | return object == m_texture; |
199 | } |
200 | |
201 | bool WebGLTextureAttachment::isValid() const |
202 | { |
203 | return m_texture->object(); |
204 | } |
205 | |
206 | bool WebGLTextureAttachment::isInitialized() const |
207 | { |
208 | // Textures are assumed to be initialized. |
209 | return true; |
210 | } |
211 | |
212 | void WebGLTextureAttachment::setInitialized() |
213 | { |
214 | // Textures are assumed to be initialized. |
215 | } |
216 | |
217 | void WebGLTextureAttachment::onDetached(GraphicsContext3D* context) |
218 | { |
219 | m_texture->onDetached(context); |
220 | } |
221 | |
222 | void WebGLTextureAttachment::attach(GraphicsContext3D* context, GC3Denum attachment) |
223 | { |
224 | Platform3DObject object = objectOrZero(m_texture.get()); |
225 | context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, attachment, m_target, object, m_level); |
226 | } |
227 | |
228 | void WebGLTextureAttachment::unattach(GraphicsContext3D* context, GC3Denum attachment) |
229 | { |
230 | if (attachment == GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT) { |
231 | context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, m_target, 0, m_level); |
232 | context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, m_target, 0, m_level); |
233 | } else |
234 | context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, attachment, m_target, 0, m_level); |
235 | } |
236 | |
237 | bool isAttachmentComplete(WebGLFramebuffer::WebGLAttachment* attachedObject, GC3Denum attachment, const char** reason) |
238 | { |
239 | ASSERT(attachedObject && attachedObject->isValid()); |
240 | ASSERT(reason); |
241 | GC3Denum format = attachedObject->getFormat(); |
242 | unsigned need = GraphicsContext3D::getClearBitsByAttachmentType(attachment); |
243 | unsigned have = GraphicsContext3D::getClearBitsByFormat(format); |
244 | |
245 | if ((need & have) != need) { |
246 | *reason = "attachment type is not correct for attachment" ; |
247 | return false; |
248 | } |
249 | if (!attachedObject->getWidth() || !attachedObject->getHeight()) { |
250 | *reason = "attachment has a 0 dimension" ; |
251 | return false; |
252 | } |
253 | if ((attachment == GraphicsContext3D::DEPTH_ATTACHMENT || attachment == GraphicsContext3D::STENCIL_ATTACHMENT) |
254 | && format == GraphicsContext3D::DEPTH_STENCIL) { |
255 | *reason = "attachment DEPTH_STENCIL not allowed on DEPTH or STENCIL attachment" ; |
256 | return false; |
257 | } |
258 | return true; |
259 | } |
260 | |
261 | } // anonymous namespace |
262 | |
263 | WebGLFramebuffer::WebGLAttachment::WebGLAttachment() = default; |
264 | |
265 | WebGLFramebuffer::WebGLAttachment::~WebGLAttachment() = default; |
266 | |
267 | Ref<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContextBase& ctx) |
268 | { |
269 | return adoptRef(*new WebGLFramebuffer(ctx)); |
270 | } |
271 | |
272 | WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContextBase& ctx) |
273 | : WebGLContextObject(ctx) |
274 | , m_hasEverBeenBound(false) |
275 | { |
276 | setObject(ctx.graphicsContext3D()->createFramebuffer()); |
277 | } |
278 | |
279 | WebGLFramebuffer::~WebGLFramebuffer() |
280 | { |
281 | deleteObject(0); |
282 | } |
283 | |
284 | void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GC3Denum attachment, GC3Denum texTarget, WebGLTexture* texture, GC3Dint level) |
285 | { |
286 | ASSERT(isBound()); |
287 | removeAttachmentFromBoundFramebuffer(attachment); |
288 | if (!object()) |
289 | return; |
290 | if (texture && texture->object()) { |
291 | m_attachments.add(attachment, WebGLTextureAttachment::create(texture, texTarget, level)); |
292 | drawBuffersIfNecessary(false); |
293 | texture->onAttached(); |
294 | } |
295 | } |
296 | |
297 | void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GC3Denum attachment, WebGLRenderbuffer* renderbuffer) |
298 | { |
299 | ASSERT(isBound()); |
300 | removeAttachmentFromBoundFramebuffer(attachment); |
301 | if (!object()) |
302 | return; |
303 | if (renderbuffer && renderbuffer->object()) { |
304 | m_attachments.add(attachment, WebGLRenderbufferAttachment::create(renderbuffer)); |
305 | drawBuffersIfNecessary(false); |
306 | renderbuffer->onAttached(); |
307 | } |
308 | } |
309 | |
310 | void WebGLFramebuffer::attach(GC3Denum attachment, GC3Denum attachmentPoint) |
311 | { |
312 | ASSERT(isBound()); |
313 | RefPtr<WebGLAttachment> attachmentObject = getAttachment(attachment); |
314 | if (attachmentObject) |
315 | attachmentObject->attach(context()->graphicsContext3D(), attachmentPoint); |
316 | } |
317 | |
318 | WebGLSharedObject* WebGLFramebuffer::getAttachmentObject(GC3Denum attachment) const |
319 | { |
320 | if (!object()) |
321 | return 0; |
322 | RefPtr<WebGLAttachment> attachmentObject = getAttachment(attachment); |
323 | return attachmentObject ? attachmentObject->getObject() : 0; |
324 | } |
325 | |
326 | WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment(GC3Denum attachment) const |
327 | { |
328 | const AttachmentMap::const_iterator it = m_attachments.find(attachment); |
329 | return (it != m_attachments.end()) ? it->value.get() : 0; |
330 | } |
331 | |
332 | void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GC3Denum attachment) |
333 | { |
334 | ASSERT(isBound()); |
335 | if (!object()) |
336 | return; |
337 | |
338 | RefPtr<WebGLAttachment> attachmentObject = getAttachment(attachment); |
339 | if (attachmentObject) { |
340 | attachmentObject->onDetached(context()->graphicsContext3D()); |
341 | m_attachments.remove(attachment); |
342 | drawBuffersIfNecessary(false); |
343 | switch (attachment) { |
344 | case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT: |
345 | attach(GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::DEPTH_ATTACHMENT); |
346 | attach(GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::STENCIL_ATTACHMENT); |
347 | break; |
348 | case GraphicsContext3D::DEPTH_ATTACHMENT: |
349 | attach(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT, GraphicsContext3D::DEPTH_ATTACHMENT); |
350 | break; |
351 | case GraphicsContext3D::STENCIL_ATTACHMENT: |
352 | attach(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT, GraphicsContext3D::STENCIL_ATTACHMENT); |
353 | break; |
354 | } |
355 | } |
356 | } |
357 | |
358 | void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(WebGLSharedObject* attachment) |
359 | { |
360 | ASSERT(isBound()); |
361 | if (!object()) |
362 | return; |
363 | if (!attachment) |
364 | return; |
365 | |
366 | bool checkMore = true; |
367 | do { |
368 | checkMore = false; |
369 | for (auto& entry : m_attachments) { |
370 | RefPtr<WebGLAttachment> attachmentObject = entry.value.get(); |
371 | if (attachmentObject->isSharedObject(attachment)) { |
372 | GC3Denum attachmentType = entry.key; |
373 | attachmentObject->unattach(context()->graphicsContext3D(), attachmentType); |
374 | removeAttachmentFromBoundFramebuffer(attachmentType); |
375 | checkMore = true; |
376 | break; |
377 | } |
378 | } |
379 | } while (checkMore); |
380 | } |
381 | |
382 | GC3Dsizei WebGLFramebuffer::getColorBufferWidth() const |
383 | { |
384 | if (!object()) |
385 | return 0; |
386 | RefPtr<WebGLAttachment> attachment = getAttachment(GraphicsContext3D::COLOR_ATTACHMENT0); |
387 | if (!attachment) |
388 | return 0; |
389 | |
390 | return attachment->getWidth(); |
391 | } |
392 | |
393 | GC3Dsizei WebGLFramebuffer::getColorBufferHeight() const |
394 | { |
395 | if (!object()) |
396 | return 0; |
397 | RefPtr<WebGLAttachment> attachment = getAttachment(GraphicsContext3D::COLOR_ATTACHMENT0); |
398 | if (!attachment) |
399 | return 0; |
400 | |
401 | return attachment->getHeight(); |
402 | } |
403 | |
404 | GC3Denum WebGLFramebuffer::getColorBufferFormat() const |
405 | { |
406 | if (!object()) |
407 | return 0; |
408 | RefPtr<WebGLAttachment> attachment = getAttachment(GraphicsContext3D::COLOR_ATTACHMENT0); |
409 | if (!attachment) |
410 | return 0; |
411 | return attachment->getFormat(); |
412 | } |
413 | |
414 | GC3Denum WebGLFramebuffer::checkStatus(const char** reason) const |
415 | { |
416 | unsigned int count = 0; |
417 | GC3Dsizei width = 0, height = 0; |
418 | bool haveDepth = false; |
419 | bool haveStencil = false; |
420 | bool haveDepthStencil = false; |
421 | for (auto& entry : m_attachments) { |
422 | RefPtr<WebGLAttachment> attachment = entry.value.get(); |
423 | if (!isAttachmentComplete(attachment.get(), entry.key, reason)) |
424 | return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT; |
425 | if (!attachment->isValid()) { |
426 | *reason = "attachment is not valid" ; |
427 | return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED; |
428 | } |
429 | GC3Denum attachmentFormat = attachment->getFormat(); |
430 | |
431 | // Attaching an SRGB_EXT format attachment to a framebuffer is invalid. |
432 | if (attachmentFormat == Extensions3D::SRGB_EXT) |
433 | attachmentFormat = 0; |
434 | |
435 | if (!attachmentFormat) { |
436 | *reason = "attachment is an unsupported format" ; |
437 | return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT; |
438 | } |
439 | switch (entry.key) { |
440 | case GraphicsContext3D::DEPTH_ATTACHMENT: |
441 | haveDepth = true; |
442 | break; |
443 | case GraphicsContext3D::STENCIL_ATTACHMENT: |
444 | haveStencil = true; |
445 | break; |
446 | case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT: |
447 | haveDepthStencil = true; |
448 | break; |
449 | } |
450 | if (!count) { |
451 | width = attachment->getWidth(); |
452 | height = attachment->getHeight(); |
453 | } else { |
454 | if (width != attachment->getWidth() || height != attachment->getHeight()) { |
455 | *reason = "attachments do not have the same dimensions" ; |
456 | return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_DIMENSIONS; |
457 | } |
458 | } |
459 | ++count; |
460 | } |
461 | if (!count) { |
462 | *reason = "no attachments" ; |
463 | return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; |
464 | } |
465 | if (!width || !height) { |
466 | *reason = "framebuffer has a 0 dimension" ; |
467 | return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT; |
468 | } |
469 | // WebGL specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments. |
470 | if ((haveDepthStencil && (haveDepth || haveStencil)) || (haveDepth && haveStencil)) { |
471 | *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments" ; |
472 | return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED; |
473 | } |
474 | return GraphicsContext3D::FRAMEBUFFER_COMPLETE; |
475 | } |
476 | |
477 | bool WebGLFramebuffer::onAccess(GraphicsContext3D* context3d, const char** reason) |
478 | { |
479 | if (checkStatus(reason) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) |
480 | return false; |
481 | return initializeAttachments(context3d, reason); |
482 | } |
483 | |
484 | bool WebGLFramebuffer::hasStencilBuffer() const |
485 | { |
486 | RefPtr<WebGLAttachment> attachment = getAttachment(GraphicsContext3D::STENCIL_ATTACHMENT); |
487 | if (!attachment) |
488 | attachment = getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT); |
489 | return attachment && attachment->isValid(); |
490 | } |
491 | |
492 | void WebGLFramebuffer::deleteObjectImpl(GraphicsContext3D* context3d, Platform3DObject object) |
493 | { |
494 | for (auto& attachment : m_attachments.values()) |
495 | attachment->onDetached(context3d); |
496 | |
497 | context3d->deleteFramebuffer(object); |
498 | } |
499 | |
500 | bool WebGLFramebuffer::initializeAttachments(GraphicsContext3D* g3d, const char** reason) |
501 | { |
502 | ASSERT(object()); |
503 | GC3Dbitfield mask = 0; |
504 | |
505 | for (auto& entry : m_attachments) { |
506 | GC3Denum attachmentType = entry.key; |
507 | RefPtr<WebGLAttachment> attachment = entry.value.get(); |
508 | if (!attachment->isInitialized()) |
509 | mask |= GraphicsContext3D::getClearBitsByAttachmentType(attachmentType); |
510 | } |
511 | if (!mask) |
512 | return true; |
513 | |
514 | // We only clear un-initialized renderbuffers when they are ready to be |
515 | // read, i.e., when the framebuffer is complete. |
516 | if (g3d->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { |
517 | *reason = "framebuffer not complete" ; |
518 | return false; |
519 | } |
520 | |
521 | bool initColor = mask & GraphicsContext3D::COLOR_BUFFER_BIT; |
522 | bool initDepth = mask & GraphicsContext3D::DEPTH_BUFFER_BIT; |
523 | bool initStencil = mask & GraphicsContext3D::STENCIL_BUFFER_BIT; |
524 | |
525 | GC3Dfloat colorClearValue[] = {0, 0, 0, 0}, depthClearValue = 0; |
526 | GC3Dint stencilClearValue = 0; |
527 | GC3Dboolean colorMask[] = {0, 0, 0, 0}, depthMask = 0; |
528 | GC3Duint stencilMask = 0xffffffff; |
529 | GC3Dboolean isScissorEnabled = 0; |
530 | GC3Dboolean isDitherEnabled = 0; |
531 | if (initColor) { |
532 | g3d->getFloatv(GraphicsContext3D::COLOR_CLEAR_VALUE, colorClearValue); |
533 | g3d->getBooleanv(GraphicsContext3D::COLOR_WRITEMASK, colorMask); |
534 | g3d->clearColor(0, 0, 0, 0); |
535 | g3d->colorMask(true, true, true, true); |
536 | } |
537 | if (initDepth) { |
538 | g3d->getFloatv(GraphicsContext3D::DEPTH_CLEAR_VALUE, &depthClearValue); |
539 | g3d->getBooleanv(GraphicsContext3D::DEPTH_WRITEMASK, &depthMask); |
540 | g3d->clearDepth(1.0f); |
541 | g3d->depthMask(true); |
542 | } |
543 | if (initStencil) { |
544 | g3d->getIntegerv(GraphicsContext3D::STENCIL_CLEAR_VALUE, &stencilClearValue); |
545 | g3d->getIntegerv(GraphicsContext3D::STENCIL_WRITEMASK, reinterpret_cast<GC3Dint*>(&stencilMask)); |
546 | g3d->clearStencil(0); |
547 | g3d->stencilMask(0xffffffff); |
548 | } |
549 | isScissorEnabled = g3d->isEnabled(GraphicsContext3D::SCISSOR_TEST); |
550 | g3d->disable(GraphicsContext3D::SCISSOR_TEST); |
551 | isDitherEnabled = g3d->isEnabled(GraphicsContext3D::DITHER); |
552 | g3d->disable(GraphicsContext3D::DITHER); |
553 | |
554 | g3d->clear(mask); |
555 | |
556 | if (initColor) { |
557 | g3d->clearColor(colorClearValue[0], colorClearValue[1], colorClearValue[2], colorClearValue[3]); |
558 | g3d->colorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]); |
559 | } |
560 | if (initDepth) { |
561 | g3d->clearDepth(depthClearValue); |
562 | g3d->depthMask(depthMask); |
563 | } |
564 | if (initStencil) { |
565 | g3d->clearStencil(stencilClearValue); |
566 | g3d->stencilMask(stencilMask); |
567 | } |
568 | if (isScissorEnabled) |
569 | g3d->enable(GraphicsContext3D::SCISSOR_TEST); |
570 | else |
571 | g3d->disable(GraphicsContext3D::SCISSOR_TEST); |
572 | if (isDitherEnabled) |
573 | g3d->enable(GraphicsContext3D::DITHER); |
574 | else |
575 | g3d->disable(GraphicsContext3D::DITHER); |
576 | |
577 | for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) { |
578 | GC3Denum attachmentType = it->key; |
579 | auto attachment = it->value; |
580 | GC3Dbitfield bits = GraphicsContext3D::getClearBitsByAttachmentType(attachmentType); |
581 | if (bits & mask) |
582 | attachment->setInitialized(); |
583 | } |
584 | return true; |
585 | } |
586 | |
587 | bool WebGLFramebuffer::isBound() const |
588 | { |
589 | return (context()->m_framebufferBinding.get() == this) || (context()->m_readFramebufferBinding.get() == this); |
590 | } |
591 | |
592 | void WebGLFramebuffer::drawBuffers(const Vector<GC3Denum>& bufs) |
593 | { |
594 | m_drawBuffers = bufs; |
595 | m_filteredDrawBuffers.resize(m_drawBuffers.size()); |
596 | for (auto& buffer : m_filteredDrawBuffers) |
597 | buffer = GraphicsContext3D::NONE; |
598 | drawBuffersIfNecessary(true); |
599 | } |
600 | |
601 | void WebGLFramebuffer::drawBuffersIfNecessary(bool force) |
602 | { |
603 | #if ENABLE(WEBGL2) |
604 | // FIXME: The logic here seems wrong. If we don't have WebGL 2 enabled at all, then |
605 | // we skip the m_webglDrawBuffers check. But if we do have WebGL 2 enabled, then we |
606 | // perform this check, for WebGL 1 contexts only. |
607 | if (!context()->m_webglDrawBuffers && !context()->isWebGL2()) |
608 | return; |
609 | #endif |
610 | bool reset = force; |
611 | // This filtering works around graphics driver bugs on Mac OS X. |
612 | for (size_t i = 0; i < m_drawBuffers.size(); ++i) { |
613 | if (m_drawBuffers[i] != GraphicsContext3D::NONE && getAttachment(m_drawBuffers[i])) { |
614 | if (m_filteredDrawBuffers[i] != m_drawBuffers[i]) { |
615 | m_filteredDrawBuffers[i] = m_drawBuffers[i]; |
616 | reset = true; |
617 | } |
618 | } else { |
619 | if (m_filteredDrawBuffers[i] != GraphicsContext3D::NONE) { |
620 | m_filteredDrawBuffers[i] = GraphicsContext3D::NONE; |
621 | reset = true; |
622 | } |
623 | } |
624 | } |
625 | if (reset) { |
626 | context()->graphicsContext3D()->getExtensions().drawBuffersEXT( |
627 | m_filteredDrawBuffers.size(), m_filteredDrawBuffers.data()); |
628 | } |
629 | } |
630 | |
631 | GC3Denum WebGLFramebuffer::getDrawBuffer(GC3Denum drawBuffer) |
632 | { |
633 | int index = static_cast<int>(drawBuffer - Extensions3D::DRAW_BUFFER0_EXT); |
634 | ASSERT(index >= 0); |
635 | if (index < static_cast<int>(m_drawBuffers.size())) |
636 | return m_drawBuffers[index]; |
637 | if (drawBuffer == Extensions3D::DRAW_BUFFER0_EXT) |
638 | return GraphicsContext3D::COLOR_ATTACHMENT0; |
639 | return GraphicsContext3D::NONE; |
640 | } |
641 | |
642 | } |
643 | |
644 | #endif // ENABLE(WEBGL) |
645 | |