OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2009 Apple Inc. All rights reserved. | 2 * Copyright (C) 2009 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 | 201 |
202 WebGLFramebuffer* WebGLFramebuffer::create(WebGLRenderingContextBase* ctx) { | 202 WebGLFramebuffer* WebGLFramebuffer::create(WebGLRenderingContextBase* ctx) { |
203 return new WebGLFramebuffer(ctx); | 203 return new WebGLFramebuffer(ctx); |
204 } | 204 } |
205 | 205 |
206 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContextBase* ctx) | 206 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContextBase* ctx) |
207 : WebGLContextObject(ctx), | 207 : WebGLContextObject(ctx), |
208 m_object(0), | 208 m_object(0), |
209 m_destructionInProgress(false), | 209 m_destructionInProgress(false), |
210 m_hasEverBeenBound(false), | 210 m_hasEverBeenBound(false), |
| 211 m_webGL1DepthStencilConsistent(true), |
211 m_readBuffer(GL_COLOR_ATTACHMENT0) { | 212 m_readBuffer(GL_COLOR_ATTACHMENT0) { |
212 ctx->contextGL()->GenFramebuffers(1, &m_object); | 213 ctx->contextGL()->GenFramebuffers(1, &m_object); |
213 } | 214 } |
214 | 215 |
215 WebGLFramebuffer::~WebGLFramebuffer() { | 216 WebGLFramebuffer::~WebGLFramebuffer() { |
216 // Attachments in |m_attachments| will be deleted from other | 217 // Attachments in |m_attachments| will be deleted from other |
217 // places, and we must not touch that map in deleteObjectImpl once | 218 // places, and we must not touch that map in deleteObjectImpl once |
218 // the destructor has been entered. | 219 // the destructor has been entered. |
219 m_destructionInProgress = true; | 220 m_destructionInProgress = true; |
220 | 221 |
221 // See the comment in WebGLObject::detachAndDeleteObject(). | 222 // See the comment in WebGLObject::detachAndDeleteObject(). |
222 detachAndDeleteObject(); | 223 detachAndDeleteObject(); |
223 } | 224 } |
224 | 225 |
225 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum target, | 226 void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GLenum target, |
226 GLenum attachment, | 227 GLenum attachment, |
227 GLenum texTarget, | 228 GLenum texTarget, |
228 WebGLTexture* texture, | 229 WebGLTexture* texture, |
229 GLint level, | 230 GLint level, |
230 GLint layer) { | 231 GLint layer) { |
231 ASSERT(isBound(target)); | 232 DCHECK(m_object); |
232 removeAttachmentFromBoundFramebuffer(target, attachment); | 233 DCHECK(isBound(target)); |
233 if (!m_object) | 234 if (context()->isWebGL2OrHigher()) { |
234 return; | 235 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { |
235 if (texture && texture->object()) { | 236 setAttachmentInternal(target, GL_DEPTH_ATTACHMENT, texTarget, texture, |
236 m_attachments.add(attachment, WebGLTextureAttachment::create( | 237 level, layer); |
237 texture, texTarget, level, layer)); | 238 setAttachmentInternal(target, GL_STENCIL_ATTACHMENT, texTarget, texture, |
238 drawBuffersIfNecessary(false); | 239 level, layer); |
239 texture->onAttached(); | 240 } else { |
| 241 setAttachmentInternal(target, attachment, texTarget, texture, level, |
| 242 layer); |
| 243 } |
| 244 GLuint textureId = objectOrZero(texture); |
| 245 // texTarget can be 0 if detaching using framebufferTextureLayer. |
| 246 DCHECK(texTarget || !textureId); |
| 247 switch (texTarget) { |
| 248 case 0: |
| 249 case GL_TEXTURE_3D: |
| 250 case GL_TEXTURE_2D_ARRAY: |
| 251 context()->contextGL()->FramebufferTextureLayer( |
| 252 target, attachment, textureId, level, layer); |
| 253 break; |
| 254 default: |
| 255 DCHECK_EQ(layer, 0); |
| 256 context()->contextGL()->FramebufferTexture2D( |
| 257 target, attachment, texTarget, textureId, level); |
| 258 break; |
| 259 } |
| 260 } else { |
| 261 DCHECK_EQ(layer, 0); |
| 262 setAttachmentInternal(target, attachment, texTarget, texture, level, layer); |
| 263 switch (attachment) { |
| 264 case GL_DEPTH_ATTACHMENT: |
| 265 case GL_STENCIL_ATTACHMENT: |
| 266 case GL_DEPTH_STENCIL_ATTACHMENT: |
| 267 commitWebGL1DepthStencilIfConsistent(target); |
| 268 break; |
| 269 default: |
| 270 context()->contextGL()->FramebufferTexture2D( |
| 271 target, attachment, texTarget, objectOrZero(texture), level); |
| 272 break; |
| 273 } |
240 } | 274 } |
241 } | 275 } |
242 | 276 |
243 void WebGLFramebuffer::setAttachmentForBoundFramebuffer( | 277 void WebGLFramebuffer::setAttachmentForBoundFramebuffer( |
244 GLenum target, | 278 GLenum target, |
245 GLenum attachment, | 279 GLenum attachment, |
246 WebGLRenderbuffer* renderbuffer) { | 280 WebGLRenderbuffer* renderbuffer) { |
247 ASSERT(isBound(target)); | 281 DCHECK(m_object); |
248 removeAttachmentFromBoundFramebuffer(target, attachment); | 282 DCHECK(isBound(target)); |
249 if (!m_object) | 283 if (context()->isWebGL2OrHigher()) { |
250 return; | 284 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { |
251 if (renderbuffer && renderbuffer->object()) { | 285 setAttachmentInternal(target, GL_DEPTH_ATTACHMENT, renderbuffer); |
252 m_attachments.add(attachment, | 286 setAttachmentInternal(target, GL_STENCIL_ATTACHMENT, renderbuffer); |
253 WebGLRenderbufferAttachment::create(renderbuffer)); | 287 } else { |
254 drawBuffersIfNecessary(false); | 288 setAttachmentInternal(target, attachment, renderbuffer); |
255 renderbuffer->onAttached(); | 289 } |
| 290 context()->contextGL()->FramebufferRenderbuffer( |
| 291 target, attachment, GL_RENDERBUFFER, objectOrZero(renderbuffer)); |
| 292 } else { |
| 293 setAttachmentInternal(target, attachment, renderbuffer); |
| 294 switch (attachment) { |
| 295 case GL_DEPTH_ATTACHMENT: |
| 296 case GL_STENCIL_ATTACHMENT: |
| 297 case GL_DEPTH_STENCIL_ATTACHMENT: |
| 298 commitWebGL1DepthStencilIfConsistent(target); |
| 299 break; |
| 300 default: |
| 301 context()->contextGL()->FramebufferRenderbuffer( |
| 302 target, attachment, GL_RENDERBUFFER, objectOrZero(renderbuffer)); |
| 303 break; |
| 304 } |
256 } | 305 } |
257 } | 306 } |
258 | 307 |
259 void WebGLFramebuffer::attach(GLenum target, | |
260 GLenum attachment, | |
261 GLenum attachmentPoint) { | |
262 ASSERT(isBound(target)); | |
263 WebGLAttachment* attachmentObject = getAttachment(attachment); | |
264 if (attachmentObject) | |
265 attachmentObject->attach(context()->contextGL(), target, attachmentPoint); | |
266 } | |
267 | |
268 WebGLSharedObject* WebGLFramebuffer::getAttachmentObject( | 308 WebGLSharedObject* WebGLFramebuffer::getAttachmentObject( |
269 GLenum attachment) const { | 309 GLenum attachment) const { |
270 if (!m_object) | 310 if (!m_object) |
271 return nullptr; | 311 return nullptr; |
272 WebGLAttachment* attachmentObject = getAttachment(attachment); | 312 WebGLAttachment* attachmentObject = getAttachment(attachment); |
273 return attachmentObject ? attachmentObject->object() : nullptr; | 313 return attachmentObject ? attachmentObject->object() : nullptr; |
274 } | 314 } |
275 | 315 |
276 WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment( | 316 WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment( |
277 GLenum attachment) const { | 317 GLenum attachment) const { |
278 const AttachmentMap::const_iterator it = m_attachments.find(attachment); | 318 const AttachmentMap::const_iterator it = m_attachments.find(attachment); |
279 return (it != m_attachments.end()) ? it->value.get() : 0; | 319 return (it != m_attachments.end()) ? it->value.get() : 0; |
280 } | 320 } |
281 | 321 |
282 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GLenum target, | |
283 GLenum attachment) { | |
284 ASSERT(isBound(target)); | |
285 if (!m_object) | |
286 return; | |
287 | |
288 WebGLAttachment* attachmentObject = getAttachment(attachment); | |
289 if (attachmentObject) { | |
290 attachmentObject->onDetached(context()->contextGL()); | |
291 m_attachments.remove(attachment); | |
292 drawBuffersIfNecessary(false); | |
293 switch (attachment) { | |
294 case GL_DEPTH_STENCIL_ATTACHMENT: | |
295 attach(target, GL_DEPTH_ATTACHMENT, GL_DEPTH_ATTACHMENT); | |
296 attach(target, GL_STENCIL_ATTACHMENT, GL_STENCIL_ATTACHMENT); | |
297 break; | |
298 case GL_DEPTH_ATTACHMENT: | |
299 case GL_STENCIL_ATTACHMENT: | |
300 attach(target, GL_DEPTH_STENCIL_ATTACHMENT, | |
301 GL_DEPTH_STENCIL_ATTACHMENT); | |
302 break; | |
303 } | |
304 } | |
305 } | |
306 | |
307 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer( | 322 void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer( |
308 GLenum target, | 323 GLenum target, |
309 WebGLSharedObject* attachment) { | 324 WebGLSharedObject* attachment) { |
310 ASSERT(isBound(target)); | 325 ASSERT(isBound(target)); |
311 if (!m_object) | 326 if (!m_object) |
312 return; | 327 return; |
313 if (!attachment) | 328 if (!attachment) |
314 return; | 329 return; |
315 | 330 |
316 bool checkMore = true; | 331 bool checkMore = true; |
| 332 bool isWebGL1 = !context()->isWebGL2OrHigher(); |
| 333 bool checkWebGL1DepthStencil = false; |
317 while (checkMore) { | 334 while (checkMore) { |
318 checkMore = false; | 335 checkMore = false; |
319 for (const auto& it : m_attachments) { | 336 for (const auto& it : m_attachments) { |
320 WebGLAttachment* attachmentObject = it.value.get(); | 337 WebGLAttachment* attachmentObject = it.value.get(); |
321 if (attachmentObject->isSharedObject(attachment)) { | 338 if (attachmentObject->isSharedObject(attachment)) { |
322 GLenum attachmentType = it.key; | 339 GLenum attachmentType = it.key; |
323 attachmentObject->unattach(context()->contextGL(), target, | 340 switch (attachmentType) { |
324 attachmentType); | 341 case GL_DEPTH_ATTACHMENT: |
325 removeAttachmentFromBoundFramebuffer(target, attachmentType); | 342 case GL_STENCIL_ATTACHMENT: |
| 343 case GL_DEPTH_STENCIL_ATTACHMENT: |
| 344 if (isWebGL1) { |
| 345 checkWebGL1DepthStencil = true; |
| 346 } else { |
| 347 attachmentObject->unattach(context()->contextGL(), target, |
| 348 attachmentType); |
| 349 } |
| 350 break; |
| 351 default: |
| 352 attachmentObject->unattach(context()->contextGL(), target, |
| 353 attachmentType); |
| 354 break; |
| 355 } |
| 356 removeAttachmentInternal(target, attachmentType); |
326 checkMore = true; | 357 checkMore = true; |
327 break; | 358 break; |
328 } | 359 } |
329 } | 360 } |
330 } | 361 } |
| 362 if (checkWebGL1DepthStencil) |
| 363 commitWebGL1DepthStencilIfConsistent(target); |
331 } | 364 } |
332 | 365 |
333 GLenum WebGLFramebuffer::checkDepthStencilStatus(const char** reason) const { | 366 GLenum WebGLFramebuffer::checkDepthStencilStatus(const char** reason) const { |
334 if (context()->isWebGL2OrHigher()) | 367 if (context()->isWebGL2OrHigher() || m_webGL1DepthStencilConsistent) |
335 return GL_FRAMEBUFFER_COMPLETE; | 368 return GL_FRAMEBUFFER_COMPLETE; |
336 WebGLAttachment* depthAttachment = nullptr; | 369 *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments"; |
337 WebGLAttachment* stencilAttachment = nullptr; | 370 return GL_FRAMEBUFFER_UNSUPPORTED; |
338 WebGLAttachment* depthStencilAttachment = nullptr; | |
339 for (const auto& it : m_attachments) { | |
340 WebGLAttachment* attachment = it.value.get(); | |
341 ASSERT(attachment); | |
342 switch (it.key) { | |
343 case GL_DEPTH_ATTACHMENT: | |
344 depthAttachment = attachment; | |
345 break; | |
346 case GL_STENCIL_ATTACHMENT: | |
347 stencilAttachment = attachment; | |
348 break; | |
349 case GL_DEPTH_STENCIL_ATTACHMENT: | |
350 depthStencilAttachment = attachment; | |
351 break; | |
352 default: | |
353 break; | |
354 } | |
355 } | |
356 if ((depthStencilAttachment && (depthAttachment || stencilAttachment)) || | |
357 (depthAttachment && stencilAttachment)) { | |
358 *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments"; | |
359 return GL_FRAMEBUFFER_UNSUPPORTED; | |
360 } | |
361 return GL_FRAMEBUFFER_COMPLETE; | |
362 } | 371 } |
363 | 372 |
364 bool WebGLFramebuffer::hasStencilBuffer() const { | 373 bool WebGLFramebuffer::hasStencilBuffer() const { |
365 WebGLAttachment* attachment = getAttachment(GL_STENCIL_ATTACHMENT); | 374 WebGLAttachment* attachment = getAttachment(GL_STENCIL_ATTACHMENT); |
366 if (!attachment) | 375 if (!attachment) |
367 attachment = getAttachment(GL_DEPTH_STENCIL_ATTACHMENT); | 376 attachment = getAttachment(GL_DEPTH_STENCIL_ATTACHMENT); |
368 return attachment && attachment->valid(); | 377 return attachment && attachment->valid(); |
369 } | 378 } |
370 | 379 |
371 void WebGLFramebuffer::deleteObjectImpl(gpu::gles2::GLES2Interface* gl) { | 380 void WebGLFramebuffer::deleteObjectImpl(gpu::gles2::GLES2Interface* gl) { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
413 } | 422 } |
414 } | 423 } |
415 } | 424 } |
416 if (reset) { | 425 if (reset) { |
417 context()->contextGL()->DrawBuffersEXT(m_filteredDrawBuffers.size(), | 426 context()->contextGL()->DrawBuffersEXT(m_filteredDrawBuffers.size(), |
418 m_filteredDrawBuffers.data()); | 427 m_filteredDrawBuffers.data()); |
419 } | 428 } |
420 } | 429 } |
421 } | 430 } |
422 | 431 |
| 432 void WebGLFramebuffer::setAttachmentInternal(GLenum target, |
| 433 GLenum attachment, |
| 434 GLenum texTarget, |
| 435 WebGLTexture* texture, |
| 436 GLint level, |
| 437 GLint layer) { |
| 438 DCHECK(isBound(target)); |
| 439 DCHECK(m_object); |
| 440 removeAttachmentInternal(target, attachment); |
| 441 if (texture && texture->object()) { |
| 442 m_attachments.add(attachment, WebGLTextureAttachment::create( |
| 443 texture, texTarget, level, layer)); |
| 444 drawBuffersIfNecessary(false); |
| 445 texture->onAttached(); |
| 446 } |
| 447 } |
| 448 |
| 449 void WebGLFramebuffer::setAttachmentInternal(GLenum target, |
| 450 GLenum attachment, |
| 451 WebGLRenderbuffer* renderbuffer) { |
| 452 DCHECK(isBound(target)); |
| 453 DCHECK(m_object); |
| 454 removeAttachmentInternal(target, attachment); |
| 455 if (renderbuffer && renderbuffer->object()) { |
| 456 m_attachments.add(attachment, |
| 457 WebGLRenderbufferAttachment::create(renderbuffer)); |
| 458 drawBuffersIfNecessary(false); |
| 459 renderbuffer->onAttached(); |
| 460 } |
| 461 } |
| 462 |
| 463 void WebGLFramebuffer::removeAttachmentInternal(GLenum target, |
| 464 GLenum attachment) { |
| 465 DCHECK(isBound(target)); |
| 466 DCHECK(m_object); |
| 467 |
| 468 WebGLAttachment* attachmentObject = getAttachment(attachment); |
| 469 if (attachmentObject) { |
| 470 attachmentObject->onDetached(context()->contextGL()); |
| 471 m_attachments.remove(attachment); |
| 472 drawBuffersIfNecessary(false); |
| 473 } |
| 474 } |
| 475 |
| 476 void WebGLFramebuffer::commitWebGL1DepthStencilIfConsistent(GLenum target) { |
| 477 DCHECK(!context()->isWebGL2OrHigher()); |
| 478 WebGLAttachment* depthAttachment = nullptr; |
| 479 WebGLAttachment* stencilAttachment = nullptr; |
| 480 WebGLAttachment* depthStencilAttachment = nullptr; |
| 481 int count = 0; |
| 482 for (const auto& it : m_attachments) { |
| 483 WebGLAttachment* attachment = it.value.get(); |
| 484 DCHECK(attachment); |
| 485 switch (it.key) { |
| 486 case GL_DEPTH_ATTACHMENT: |
| 487 depthAttachment = attachment; |
| 488 ++count; |
| 489 break; |
| 490 case GL_STENCIL_ATTACHMENT: |
| 491 stencilAttachment = attachment; |
| 492 ++count; |
| 493 break; |
| 494 case GL_DEPTH_STENCIL_ATTACHMENT: |
| 495 depthStencilAttachment = attachment; |
| 496 ++count; |
| 497 break; |
| 498 default: |
| 499 break; |
| 500 } |
| 501 } |
| 502 |
| 503 m_webGL1DepthStencilConsistent = count <= 1; |
| 504 if (!m_webGL1DepthStencilConsistent) |
| 505 return; |
| 506 |
| 507 gpu::gles2::GLES2Interface* gl = context()->contextGL(); |
| 508 if (depthAttachment) { |
| 509 depthAttachment->attach(gl, target, GL_DEPTH_ATTACHMENT); |
| 510 gl->FramebufferRenderbuffer(target, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| 511 0); |
| 512 } else if (stencilAttachment) { |
| 513 gl->FramebufferRenderbuffer(target, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, |
| 514 0); |
| 515 stencilAttachment->attach(gl, target, GL_STENCIL_ATTACHMENT); |
| 516 } else if (depthStencilAttachment) { |
| 517 depthStencilAttachment->attach(gl, target, GL_DEPTH_STENCIL_ATTACHMENT); |
| 518 } else { |
| 519 gl->FramebufferRenderbuffer(target, GL_DEPTH_STENCIL_ATTACHMENT, |
| 520 GL_RENDERBUFFER, 0); |
| 521 } |
| 522 } |
| 523 |
423 GLenum WebGLFramebuffer::getDrawBuffer(GLenum drawBuffer) { | 524 GLenum WebGLFramebuffer::getDrawBuffer(GLenum drawBuffer) { |
424 int index = static_cast<int>(drawBuffer - GL_DRAW_BUFFER0_EXT); | 525 int index = static_cast<int>(drawBuffer - GL_DRAW_BUFFER0_EXT); |
425 ASSERT(index >= 0); | 526 ASSERT(index >= 0); |
426 if (index < static_cast<int>(m_drawBuffers.size())) | 527 if (index < static_cast<int>(m_drawBuffers.size())) |
427 return m_drawBuffers[index]; | 528 return m_drawBuffers[index]; |
428 if (drawBuffer == GL_DRAW_BUFFER0_EXT) | 529 if (drawBuffer == GL_DRAW_BUFFER0_EXT) |
429 return GL_COLOR_ATTACHMENT0; | 530 return GL_COLOR_ATTACHMENT0; |
430 return GL_NONE; | 531 return GL_NONE; |
431 } | 532 } |
432 | 533 |
433 void WebGLFramebuffer::visitChildDOMWrappers( | 534 void WebGLFramebuffer::visitChildDOMWrappers( |
434 v8::Isolate* isolate, | 535 v8::Isolate* isolate, |
435 const v8::Persistent<v8::Object>& wrapper) { | 536 const v8::Persistent<v8::Object>& wrapper) { |
436 for (const auto& attachment : m_attachments) { | 537 for (const auto& attachment : m_attachments) { |
437 DOMWrapperWorld::setWrapperReferencesInAllWorlds( | 538 DOMWrapperWorld::setWrapperReferencesInAllWorlds( |
438 wrapper, attachment.value->object(), isolate); | 539 wrapper, attachment.value->object(), isolate); |
439 } | 540 } |
440 } | 541 } |
441 | 542 |
442 DEFINE_TRACE(WebGLFramebuffer) { | 543 DEFINE_TRACE(WebGLFramebuffer) { |
443 visitor->trace(m_attachments); | 544 visitor->trace(m_attachments); |
444 WebGLContextObject::trace(visitor); | 545 WebGLContextObject::trace(visitor); |
445 } | 546 } |
446 | 547 |
447 } // namespace blink | 548 } // namespace blink |
OLD | NEW |