| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2012 Google 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 * | 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 return true; | 189 return true; |
| 190 if (m_surface) // && !m_layer is implied | 190 if (m_surface) // && !m_layer is implied |
| 191 return false; | 191 return false; |
| 192 | 192 |
| 193 // Whether or not to accelerate is not yet resolved, determine whether immed
iate presentation | 193 // Whether or not to accelerate is not yet resolved, determine whether immed
iate presentation |
| 194 // of the canvas would result in the canvas being accelerated. Presentation
is assumed to be | 194 // of the canvas would result in the canvas being accelerated. Presentation
is assumed to be |
| 195 // a 'PreferAcceleration' operation. | 195 // a 'PreferAcceleration' operation. |
| 196 return shouldAccelerate(PreferAcceleration); | 196 return shouldAccelerate(PreferAcceleration); |
| 197 } | 197 } |
| 198 | 198 |
| 199 GLenum Canvas2DLayerBridge::getGLFilter() |
| 200 { |
| 201 return m_filterQuality == kNone_SkFilterQuality ? GL_NEAREST : GL_LINEAR; |
| 202 } |
| 203 |
| 204 bool Canvas2DLayerBridge::prepareIOSurfaceMailboxFromImage(RefPtr<SkImage>& imag
e, WebExternalTextureMailbox* outMailbox) |
| 205 { |
| 206 GLuint textureId, imageId; |
| 207 if (!createIOSurfaceBackedTexture(&textureId, &imageId)) |
| 208 return false; |
| 209 |
| 210 GLuint imageTexture = skia::GrBackendObjectToGrGLTextureInfo(image->getTextu
reHandle(true))->fID; |
| 211 context()->copyTextureCHROMIUM(imageTexture, textureId, GL_BGRA_EXT, GL_UNSI
GNED_BYTE, GL_FALSE, GL_FALSE, GL_FALSE); |
| 212 |
| 213 MailboxInfo& info = createMailboxInfo(); |
| 214 info.m_mailbox.textureTarget = GC3D_TEXTURE_RECTANGLE_ARB; |
| 215 context()->genMailboxCHROMIUM(info.m_mailbox.name); |
| 216 context()->produceTextureDirectCHROMIUM(textureId, info.m_mailbox.textureTar
get, info.m_mailbox.name); |
| 217 info.m_mailbox.allowOverlay = true; |
| 218 info.m_mailbox.nearestNeighbor = getGLFilter(); |
| 219 |
| 220 const WGC3Duint64 fenceSync = context()->insertFenceSyncCHROMIUM(); |
| 221 context()->flush(); |
| 222 info.m_mailbox.validSyncToken = context()->genSyncTokenCHROMIUM(fenceSync, i
nfo.m_mailbox.syncToken); |
| 223 |
| 224 info.m_CHROMIUMImageId = imageId; |
| 225 info.m_textureId = textureId; |
| 226 *outMailbox = info.m_mailbox; |
| 227 |
| 228 // Because we are changing the texture binding without going through skia, |
| 229 // we must dirty the context. |
| 230 GrContext* grContext = m_contextProvider->grContext(); |
| 231 grContext->resetContext(kTextureBinding_GrGLBackendState); |
| 232 |
| 233 return true; |
| 234 } |
| 235 |
| 236 bool Canvas2DLayerBridge::createIOSurfaceBackedTexture(GLuint* outTexture, GLuin
t* outImageId) |
| 237 { |
| 238 WebGraphicsContext3D* webContext = context(); |
| 239 GLuint imageId = webContext->createGpuMemoryBufferImageCHROMIUM(m_size.width
(), m_size.height(), GL_BGRA_EXT, GC3D_SCANOUT_CHROMIUM); |
| 240 if (!imageId) |
| 241 return false; |
| 242 |
| 243 GLuint textureId= webContext->createTexture(); |
| 244 if (!textureId) { |
| 245 webContext->destroyImageCHROMIUM(imageId); |
| 246 return false; |
| 247 } |
| 248 |
| 249 GLenum target = GC3D_TEXTURE_RECTANGLE_ARB; |
| 250 webContext->bindTexture(target, textureId); |
| 251 webContext->texParameteri(target, GL_TEXTURE_MAG_FILTER, getGLFilter()); |
| 252 webContext->texParameteri(target, GL_TEXTURE_MIN_FILTER, getGLFilter()); |
| 253 webContext->texParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 254 webContext->texParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 255 webContext->bindTexImage2DCHROMIUM(target, imageId); |
| 256 |
| 257 *outTexture = textureId; |
| 258 *outImageId = imageId; |
| 259 return true; |
| 260 } |
| 261 |
| 262 Canvas2DLayerBridge::MailboxInfo& Canvas2DLayerBridge::createMailboxInfo() |
| 263 { |
| 264 MailboxInfo tmp; |
| 265 tmp.m_parentLayerBridge = this; |
| 266 m_mailboxes.prepend(tmp); |
| 267 MailboxInfo& mailboxInfo = m_mailboxes.first(); |
| 268 return mailboxInfo; |
| 269 } |
| 270 |
| 271 bool Canvas2DLayerBridge::prepareMailboxFromImage(RefPtr<SkImage>& image, WebExt
ernalTextureMailbox* outMailbox) |
| 272 { |
| 273 GrContext* grContext = m_contextProvider->grContext(); |
| 274 if (RuntimeEnabledFeatures::canvas2dImageChromiumEnabled()) { |
| 275 if (grContext && prepareIOSurfaceMailboxFromImage(image, outMailbox)) |
| 276 return true; |
| 277 } |
| 278 |
| 279 MailboxInfo& mailboxInfo = createMailboxInfo(); |
| 280 mailboxInfo.m_mailbox.nearestNeighbor = getGLFilter() == GL_NEAREST; |
| 281 mailboxInfo.m_image = image; |
| 282 |
| 283 if (!grContext) |
| 284 return true; // for testing: skip gl stuff when using a mock graphics co
ntext. |
| 285 |
| 286 if (RuntimeEnabledFeatures::forceDisable2dCanvasCopyOnWriteEnabled()) |
| 287 m_surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode)
; |
| 288 |
| 289 // Need to flush skia's internal queue because texture is about to be access
ed directly |
| 290 grContext->flush(); |
| 291 |
| 292 // Because of texture sharing with the compositor, we must invalidate |
| 293 // the state cached in skia so that the deferred copy on write |
| 294 // in SkSurface_Gpu does not make any false assumptions. |
| 295 mailboxInfo.m_image->getTexture()->textureParamsModified(); |
| 296 mailboxInfo.m_mailbox.textureTarget = GL_TEXTURE_2D; |
| 297 |
| 298 WebGraphicsContext3D* webContext = context(); |
| 299 GLuint textureID = skia::GrBackendObjectToGrGLTextureInfo(mailboxInfo.m_imag
e->getTextureHandle(true))->fID; |
| 300 webContext->bindTexture(GL_TEXTURE_2D, textureID); |
| 301 webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getGLFilter(
)); |
| 302 webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getGLFilter(
)); |
| 303 webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE
); |
| 304 webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE
); |
| 305 |
| 306 // Re-use the texture's existing mailbox, if there is one. |
| 307 if (image->getTexture()->getCustomData()) { |
| 308 ASSERT(image->getTexture()->getCustomData()->size() == sizeof(mailboxInf
o.m_mailbox.name)); |
| 309 memcpy(&mailboxInfo.m_mailbox.name[0], image->getTexture()->getCustomDat
a()->data(), sizeof(mailboxInfo.m_mailbox.name)); |
| 310 } else { |
| 311 context()->genMailboxCHROMIUM(mailboxInfo.m_mailbox.name); |
| 312 RefPtr<SkData> mailboxNameData = adoptRef(SkData::NewWithCopy(&mailboxIn
fo.m_mailbox.name[0], sizeof(mailboxInfo.m_mailbox.name))); |
| 313 image->getTexture()->setCustomData(mailboxNameData.get()); |
| 314 webContext->produceTextureCHROMIUM(GL_TEXTURE_2D, mailboxInfo.m_mailbox.
name); |
| 315 } |
| 316 |
| 317 if (isHidden()) { |
| 318 // With hidden canvases, we release the SkImage immediately because |
| 319 // there is no need for animations to be double buffered. |
| 320 mailboxInfo.m_image.clear(); |
| 321 } else { |
| 322 // FIXME: We'd rather insert a syncpoint than perform a flush here, |
| 323 // but currently the canvas will flicker if we don't flush here. |
| 324 const WGC3Duint64 fenceSync = webContext->insertFenceSyncCHROMIUM(); |
| 325 webContext->flush(); |
| 326 mailboxInfo.m_mailbox.validSyncToken = webContext->genSyncTokenCHROMIUM(
fenceSync, mailboxInfo.m_mailbox.syncToken); |
| 327 } |
| 328 webContext->bindTexture(GL_TEXTURE_2D, 0); |
| 329 // Because we are changing the texture binding without going through skia, |
| 330 // we must dirty the context. |
| 331 grContext->resetContext(kTextureBinding_GrGLBackendState); |
| 332 |
| 333 *outMailbox = mailboxInfo.m_mailbox; |
| 334 return true; |
| 335 } |
| 336 |
| 199 static void hibernateWrapper(WeakPtr<Canvas2DLayerBridge> bridge, double /*idleD
eadline*/) | 337 static void hibernateWrapper(WeakPtr<Canvas2DLayerBridge> bridge, double /*idleD
eadline*/) |
| 200 { | 338 { |
| 201 if (bridge) { | 339 if (bridge) { |
| 202 bridge->hibernate(); | 340 bridge->hibernate(); |
| 203 } else { | 341 } else { |
| 204 Canvas2DLayerBridge::Logger localLogger; | 342 Canvas2DLayerBridge::Logger localLogger; |
| 205 localLogger.reportHibernationEvent(Canvas2DLayerBridge::HibernationAbort
edDueToDestructionWhileHibernatePending); | 343 localLogger.reportHibernationEvent(Canvas2DLayerBridge::HibernationAbort
edDueToDestructionWhileHibernatePending); |
| 206 } | 344 } |
| 207 } | 345 } |
| 208 | 346 |
| (...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 609 // not care about producing any results for this canvas. | 747 // not care about producing any results for this canvas. |
| 610 skipQueuedDrawCommands(); | 748 skipQueuedDrawCommands(); |
| 611 m_lastImageId = 0; | 749 m_lastImageId = 0; |
| 612 return false; | 750 return false; |
| 613 } | 751 } |
| 614 | 752 |
| 615 RefPtr<SkImage> image = newImageSnapshot(PreferAcceleration, SnapshotReasonU
nknown); | 753 RefPtr<SkImage> image = newImageSnapshot(PreferAcceleration, SnapshotReasonU
nknown); |
| 616 if (!image || !image->getTexture()) | 754 if (!image || !image->getTexture()) |
| 617 return false; | 755 return false; |
| 618 | 756 |
| 619 WebGraphicsContext3D* webContext = context(); | 757 // Early exit if canvas was not drawn to since last prepareMailbox. |
| 620 | 758 GLenum filter = getGLFilter(); |
| 621 // Early exit if canvas was not drawn to since last prepareMailbox | |
| 622 GLenum filter = m_filterQuality == kNone_SkFilterQuality ? GL_NEAREST : GL_L
INEAR; | |
| 623 if (image->uniqueID() == m_lastImageId && filter == m_lastFilter) | 759 if (image->uniqueID() == m_lastImageId && filter == m_lastFilter) |
| 624 return false; | 760 return false; |
| 625 m_lastImageId = image->uniqueID(); | 761 m_lastImageId = image->uniqueID(); |
| 626 m_lastFilter = filter; | 762 m_lastFilter = filter; |
| 627 | 763 |
| 628 { | 764 return prepareMailboxFromImage(image, outMailbox); |
| 629 MailboxInfo tmp; | |
| 630 tmp.m_image = image; | |
| 631 tmp.m_parentLayerBridge = this; | |
| 632 m_mailboxes.prepend(tmp); | |
| 633 } | |
| 634 MailboxInfo& mailboxInfo = m_mailboxes.first(); | |
| 635 | |
| 636 mailboxInfo.m_mailbox.nearestNeighbor = filter == GL_NEAREST; | |
| 637 | |
| 638 GrContext* grContext = m_contextProvider->grContext(); | |
| 639 if (!grContext) | |
| 640 return true; // for testing: skip gl stuff when using a mock graphics co
ntext. | |
| 641 | |
| 642 if (RuntimeEnabledFeatures::forceDisable2dCanvasCopyOnWriteEnabled()) | |
| 643 m_surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode)
; | |
| 644 | |
| 645 // Because of texture sharing with the compositor, we must invalidate | |
| 646 // the state cached in skia so that the deferred copy on write | |
| 647 // in SkSurface_Gpu does not make any false assumptions. | |
| 648 mailboxInfo.m_image->getTexture()->textureParamsModified(); | |
| 649 mailboxInfo.m_mailbox.textureTarget = GL_TEXTURE_2D; | |
| 650 | |
| 651 // Passing true because we need to flush skia's internal queue since texture
is about to be accessed directly | |
| 652 GLuint textureID = skia::GrBackendObjectToGrGLTextureInfo(mailboxInfo.m_imag
e->getTextureHandle(true))->fID; | |
| 653 webContext->bindTexture(GL_TEXTURE_2D, textureID); | |
| 654 webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); | |
| 655 webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); | |
| 656 webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE
); | |
| 657 webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE
); | |
| 658 | |
| 659 // Re-use the texture's existing mailbox, if there is one. | |
| 660 if (image->getTexture()->getCustomData()) { | |
| 661 ASSERT(image->getTexture()->getCustomData()->size() == sizeof(mailboxInf
o.m_mailbox.name)); | |
| 662 memcpy(&mailboxInfo.m_mailbox.name[0], image->getTexture()->getCustomDat
a()->data(), sizeof(mailboxInfo.m_mailbox.name)); | |
| 663 } else { | |
| 664 context()->genMailboxCHROMIUM(mailboxInfo.m_mailbox.name); | |
| 665 RefPtr<SkData> mailboxNameData = adoptRef(SkData::NewWithCopy(&mailboxIn
fo.m_mailbox.name[0], sizeof(mailboxInfo.m_mailbox.name))); | |
| 666 image->getTexture()->setCustomData(mailboxNameData.get()); | |
| 667 webContext->produceTextureCHROMIUM(GL_TEXTURE_2D, mailboxInfo.m_mailbox.
name); | |
| 668 } | |
| 669 | |
| 670 if (isHidden()) { | |
| 671 // With hidden canvases, we release the SkImage immediately because | |
| 672 // there is no need for animations to be double buffered. | |
| 673 mailboxInfo.m_image.clear(); | |
| 674 } else { | |
| 675 // FIXME: We'd rather insert a syncpoint than perform a flush here, | |
| 676 // but currently the canvas will flicker if we don't flush here. | |
| 677 const WGC3Duint64 fenceSync = webContext->insertFenceSyncCHROMIUM(); | |
| 678 webContext->flush(); | |
| 679 mailboxInfo.m_mailbox.validSyncToken = webContext->genSyncTokenCHROMIUM(
fenceSync, mailboxInfo.m_mailbox.syncToken); | |
| 680 } | |
| 681 webContext->bindTexture(GL_TEXTURE_2D, 0); | |
| 682 // Because we are changing the texture binding without going through skia, | |
| 683 // we must dirty the context. | |
| 684 grContext->resetContext(kTextureBinding_GrGLBackendState); | |
| 685 | |
| 686 *outMailbox = mailboxInfo.m_mailbox; | |
| 687 return true; | |
| 688 } | 765 } |
| 689 | 766 |
| 690 void Canvas2DLayerBridge::mailboxReleased(const WebExternalTextureMailbox& mailb
ox, bool lostResource) | 767 void Canvas2DLayerBridge::mailboxReleased(const WebExternalTextureMailbox& mailb
ox, bool lostResource) |
| 691 { | 768 { |
| 692 ASSERT(isAccelerated() || isHibernating()); | 769 ASSERT(isAccelerated() || isHibernating()); |
| 693 bool contextLost = !isHibernating() && (!m_surface || m_contextProvider->con
text3d()->isContextLost()); | 770 bool contextLost = !isHibernating() && (!m_surface || m_contextProvider->con
text3d()->isContextLost()); |
| 694 ASSERT(m_mailboxes.last().m_parentLayerBridge.get() == this); | 771 ASSERT(m_mailboxes.last().m_parentLayerBridge.get() == this); |
| 695 | 772 |
| 696 // Mailboxes are typically released in FIFO order, so we iterate | 773 // Mailboxes are typically released in FIFO order, so we iterate |
| 697 // from the end of m_mailboxes. | 774 // from the end of m_mailboxes. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 714 } | 791 } |
| 715 GrTexture* texture = releasedMailboxInfo->m_image->getTexture(); | 792 GrTexture* texture = releasedMailboxInfo->m_image->getTexture(); |
| 716 if (texture) { | 793 if (texture) { |
| 717 if (lostResource) { | 794 if (lostResource) { |
| 718 texture->abandon(); | 795 texture->abandon(); |
| 719 } else { | 796 } else { |
| 720 texture->textureParamsModified(); | 797 texture->textureParamsModified(); |
| 721 } | 798 } |
| 722 } | 799 } |
| 723 } | 800 } |
| 801 |
| 802 if (releasedMailboxInfo->m_CHROMIUMImageId) { |
| 803 ASSERT(releasedMailboxInfo->m_textureId); |
| 804 ASSERT(!releasedMailboxInfo->m_image); |
| 805 if (mailbox.validSyncToken) { |
| 806 context()->waitSyncTokenCHROMIUM(mailbox.syncToken); |
| 807 } |
| 808 |
| 809 WebGraphicsContext3D* webContext = context(); |
| 810 GLenum target = GC3D_TEXTURE_RECTANGLE_ARB; |
| 811 webContext->bindTexture(target, releasedMailboxInfo->m_textureId); |
| 812 webContext->releaseTexImage2DCHROMIUM(target, releasedMailboxInfo->m
_CHROMIUMImageId); |
| 813 webContext->destroyImageCHROMIUM(releasedMailboxInfo->m_CHROMIUMImag
eId); |
| 814 webContext->deleteTexture(releasedMailboxInfo->m_textureId); |
| 815 webContext->bindTexture(target, 0); |
| 816 |
| 817 // Because we are changing the texture binding without going through
skia, |
| 818 // we must dirty the context. |
| 819 GrContext* grContext = m_contextProvider->grContext(); |
| 820 grContext->resetContext(kTextureBinding_GrGLBackendState); |
| 821 } |
| 724 } | 822 } |
| 725 | 823 |
| 726 RefPtr<Canvas2DLayerBridge> selfRef; | 824 RefPtr<Canvas2DLayerBridge> selfRef; |
| 727 if (m_destructionInProgress) { | 825 if (m_destructionInProgress) { |
| 728 // To avoid memory use after free, take a scoped self-reference | 826 // To avoid memory use after free, take a scoped self-reference |
| 729 // to postpone destruction until the end of this function. | 827 // to postpone destruction until the end of this function. |
| 730 selfRef = this; | 828 selfRef = this; |
| 731 } | 829 } |
| 732 | 830 |
| 733 // The destruction of 'releasedMailboxInfo' will: | 831 // The destruction of 'releasedMailboxInfo' will: |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 826 void Canvas2DLayerBridge::willOverwriteCanvas() | 924 void Canvas2DLayerBridge::willOverwriteCanvas() |
| 827 { | 925 { |
| 828 skipQueuedDrawCommands(); | 926 skipQueuedDrawCommands(); |
| 829 } | 927 } |
| 830 | 928 |
| 831 Canvas2DLayerBridge::MailboxInfo::MailboxInfo(const MailboxInfo& other) | 929 Canvas2DLayerBridge::MailboxInfo::MailboxInfo(const MailboxInfo& other) |
| 832 { | 930 { |
| 833 memcpy(&m_mailbox, &other.m_mailbox, sizeof(m_mailbox)); | 931 memcpy(&m_mailbox, &other.m_mailbox, sizeof(m_mailbox)); |
| 834 m_image = other.m_image; | 932 m_image = other.m_image; |
| 835 m_parentLayerBridge = other.m_parentLayerBridge; | 933 m_parentLayerBridge = other.m_parentLayerBridge; |
| 934 m_CHROMIUMImageId = other.m_CHROMIUMImageId; |
| 935 m_textureId = other.m_textureId; |
| 836 } | 936 } |
| 837 | 937 |
| 838 void Canvas2DLayerBridge::Logger::reportHibernationEvent(HibernationEvent event) | 938 void Canvas2DLayerBridge::Logger::reportHibernationEvent(HibernationEvent event) |
| 839 { | 939 { |
| 840 DEFINE_STATIC_LOCAL(EnumerationHistogram, hibernationHistogram, ("Canvas.Hib
ernationEvents", HibernationEventCount)); | 940 DEFINE_STATIC_LOCAL(EnumerationHistogram, hibernationHistogram, ("Canvas.Hib
ernationEvents", HibernationEventCount)); |
| 841 hibernationHistogram.count(event); | 941 hibernationHistogram.count(event); |
| 842 } | 942 } |
| 843 | 943 |
| 844 } // namespace blink | 944 } // namespace blink |
| OLD | NEW |