bool ImageBuffer::copyToPlatformTexture(WebGraphicsContext3D* context, Platform3DObject texture, GLenum internalFormat, GLenum destType, GLint level, bool premultiplyAlpha, bool flipY) { if (!Extensions3DUtil::canUseCopyTextureCHROMIUM(GL_TEXTURE_2D, internalFormat, destType, level)) return false; if (!isSurfaceValid()) return false; RefPtr<const SkImage> textureImage = m_surface->newImageSnapshot(PreferAcceleration); if (!textureImage) return false; if (!m_surface->isAccelerated()) return false; ASSERT(textureImage->isTextureBacked()); // isAccelerated() check above should guarantee this // Get the texture ID, flushing pending operations if needed. Platform3DObject textureId = textureImage->getTextureHandle(true); if (!textureId) return false; OwnPtr<WebGraphicsContext3DProvider> provider = adoptPtr(Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); if (!provider) return false; WebGraphicsContext3D* sharedContext = provider->context3d(); if (!sharedContext) return false; OwnPtr<WebExternalTextureMailbox> mailbox = adoptPtr(new WebExternalTextureMailbox); // Contexts may be in a different share group. We must transfer the texture through a mailbox first sharedContext->genMailboxCHROMIUM(mailbox->name); sharedContext->produceTextureDirectCHROMIUM(textureId, GL_TEXTURE_2D, mailbox->name); sharedContext->flush(); mailbox->validSyncToken = sharedContext->insertSyncPoint(mailbox->syncToken); if (mailbox->validSyncToken) context->waitSyncToken(mailbox->syncToken); Platform3DObject sourceTexture = context->createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox->name); // The canvas is stored in a premultiplied format, so unpremultiply if necessary. // The canvas is stored in an inverted position, so the flip semantics are reversed. context->copyTextureCHROMIUM(GL_TEXTURE_2D, sourceTexture, texture, internalFormat, destType, flipY ? GL_FALSE : GL_TRUE, GL_FALSE, premultiplyAlpha ? GL_FALSE : GL_TRUE); context->deleteTexture(sourceTexture); context->flush(); WGC3Dbyte syncToken[24]; if (context->insertSyncPoint(syncToken)) sharedContext->waitSyncToken(syncToken); // Undo grContext texture binding changes introduced in this function provider->grContext()->resetContext(kTextureBinding_GrGLBackendState); return true; }
bool ImageBuffer::copyToPlatformTexture(WebGraphicsContext3D* context, Platform3DObject texture, GLenum internalFormat, GLenum destType, GLint level, bool premultiplyAlpha, bool flipY) { if (!m_surface->isAccelerated() || !getBackingTexture() || !isSurfaceValid()) return false; if (!Extensions3DUtil::canUseCopyTextureCHROMIUM(internalFormat, destType, level)) return false; OwnPtr<WebGraphicsContext3DProvider> provider = adoptPtr(Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); if (!provider) return false; WebGraphicsContext3D* sharedContext = provider->context3d(); if (!sharedContext) return false; OwnPtr<WebExternalTextureMailbox> mailbox = adoptPtr(new WebExternalTextureMailbox); // Contexts may be in a different share group. We must transfer the texture through a mailbox first sharedContext->genMailboxCHROMIUM(mailbox->name); sharedContext->produceTextureDirectCHROMIUM(getBackingTexture(), GL_TEXTURE_2D, mailbox->name); sharedContext->flush(); mailbox->syncPoint = sharedContext->insertSyncPoint(); context->waitSyncPoint(mailbox->syncPoint); Platform3DObject sourceTexture = context->createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox->name); // The canvas is stored in a premultiplied format, so unpremultiply if necessary. context->pixelStorei(GC3D_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, !premultiplyAlpha); // The canvas is stored in an inverted position, so the flip semantics are reversed. context->pixelStorei(GC3D_UNPACK_FLIP_Y_CHROMIUM, !flipY); context->copyTextureCHROMIUM(GL_TEXTURE_2D, sourceTexture, texture, level, internalFormat, destType); context->pixelStorei(GC3D_UNPACK_FLIP_Y_CHROMIUM, false); context->pixelStorei(GC3D_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, false); context->deleteTexture(sourceTexture); context->flush(); sharedContext->waitSyncPoint(context->insertSyncPoint()); // Undo grContext texture binding changes introduced in this function provider->grContext()->resetContext(kTextureBinding_GrGLBackendState); return true; }
bool Canvas2DLayerBridge::prepareMailbox(WebExternalTextureMailbox* outMailbox, WebExternalBitmap* bitmap) { if (m_destructionInProgress) { // It can be hit in the following sequence. // 1. Canvas draws something. // 2. The compositor begins the frame. // 3. Javascript makes a context be lost. // 4. Here. return false; } if (bitmap) { // Using accelerated 2d canvas with software renderer, which // should only happen in tests that use fake graphics contexts // or in Android WebView in software mode. In this case, we do // not care about producing any results for this canvas. m_canvas->silentFlush(); m_lastImageId = 0; return false; } if (!checkSurfaceValid()) return false; WebGraphicsContext3D* webContext = context(); // Release to skia textures that were previouosly released by the // compositor. We do this before acquiring the next snapshot in // order to cap maximum gpu memory consumption. flush(); RefPtr<SkImage> image = adoptRef(m_canvas->newImageSnapshot()); // Early exit if canvas was not drawn to since last prepareMailbox GLenum filter = m_filterLevel == SkPaint::kNone_FilterLevel ? GL_NEAREST : GL_LINEAR; if (image->uniqueID() == m_lastImageId && filter == m_lastFilter) return false; m_lastImageId = image->uniqueID(); m_lastFilter = filter; { MailboxInfo tmp; tmp.m_image = image; tmp.m_parentLayerBridge = this; m_mailboxes.prepend(tmp); } MailboxInfo& mailboxInfo = m_mailboxes.first(); mailboxInfo.m_mailbox.nearestNeighbor = filter == GL_NEAREST; GrContext* grContext = m_contextProvider->grContext(); if (!grContext) return true; // for testing: skip gl stuff when using a mock graphics context. ASSERT(image->getTexture()); // Because of texture sharing with the compositor, we must invalidate // the state cached in skia so that the deferred copy on write // in SkSurface_Gpu does not make any false assumptions. mailboxInfo.m_image->getTexture()->textureParamsModified(); webContext->bindTexture(GL_TEXTURE_2D, mailboxInfo.m_image->getTexture()->getTextureHandle()); webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); webContext->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Re-use the texture's existing mailbox, if there is one. if (image->getTexture()->getCustomData()) { ASSERT(image->getTexture()->getCustomData()->size() == sizeof(mailboxInfo.m_mailbox.name)); memcpy(&mailboxInfo.m_mailbox.name[0], image->getTexture()->getCustomData()->data(), sizeof(mailboxInfo.m_mailbox.name)); } else { context()->genMailboxCHROMIUM(mailboxInfo.m_mailbox.name); RefPtr<SkData> mialboxNameData = adoptRef(SkData::NewWithCopy(&mailboxInfo.m_mailbox.name[0], sizeof(mailboxInfo.m_mailbox.name))); image->getTexture()->setCustomData(mialboxNameData.get()); webContext->produceTextureCHROMIUM(GL_TEXTURE_2D, mailboxInfo.m_mailbox.name); } if (isHidden()) { // With hidden canvases, we release the SkImage immediately because // there is no need for animations to be double buffered. mailboxInfo.m_image.clear(); } else { webContext->flush(); mailboxInfo.m_mailbox.syncPoint = webContext->insertSyncPoint(); } webContext->bindTexture(GL_TEXTURE_2D, 0); // Because we are changing the texture binding without going through skia, // we must dirty the context. grContext->resetContext(kTextureBinding_GrGLBackendState); *outMailbox = mailboxInfo.m_mailbox; return true; }