bool Canvas2DLayerBridge::restoreSurface() { ASSERT(!m_destructionInProgress); if (m_destructionInProgress) return false; ASSERT(m_layer && !m_isSurfaceValid); WebGraphicsContext3D* sharedContext = 0; // We must clear the mailboxes before calling m_layer->clearTexture() to prevent // re-entry via mailboxReleased from operating on defunct GrContext objects. m_mailboxes.clear(); m_layer->clearTexture(); m_contextProvider = adoptPtr(Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); if (m_contextProvider) sharedContext = m_contextProvider->context3d(); if (sharedContext && !sharedContext->isContextLost()) { IntSize size(m_canvas->getTopDevice()->width(), m_canvas->getTopDevice()->height()); RefPtr<SkSurface> surface(createSkSurface(m_contextProvider->grContext(), size, m_msaaSampleCount, m_opacityMode)); if (surface.get()) { m_surface = surface.release(); m_canvas->setSurface(m_surface.get()); m_isSurfaceValid = true; // FIXME: draw sad canvas picture into new buffer crbug.com/243842 } } return m_isSurfaceValid; }
bool Canvas2DLayerBridge::restoreSurface() { ASSERT(!m_destructionInProgress); if (m_destructionInProgress) return false; ASSERT(isAccelerated() && !m_surface); WebGraphicsContext3D* sharedContext = 0; m_layer->clearTexture(); m_contextProvider = adoptPtr(Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); if (m_contextProvider) sharedContext = m_contextProvider->context3d(); if (sharedContext && !sharedContext->isContextLost()) { GrContext* grCtx = m_contextProvider->grContext(); bool surfaceIsAccelerated; RefPtr<SkSurface> surface(createSkSurface(grCtx, m_size, m_msaaSampleCount, m_opacityMode, &surfaceIsAccelerated)); // Current paradigm does support switching from accelerated to non-accelerated, which would be tricky // due to changes to the layer tree, which can only happen at specific times during the document lifecycle. // Therefore, we can only accept the restored surface if it is accelerated. if (surface.get() && surfaceIsAccelerated) { m_surface = surface.release(); // FIXME: draw sad canvas picture into new buffer crbug.com/243842 } } return m_surface; }
bool Canvas2DLayerBridge::restoreSurface() { ASSERT(!m_destructionInProgress); if (m_destructionInProgress) return false; ASSERT(m_layer && !m_surface); WebGraphicsContext3D* sharedContext = 0; m_layer->clearTexture(); m_contextProvider = adoptPtr(Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); if (m_contextProvider) sharedContext = m_contextProvider->context3d(); if (sharedContext && !sharedContext->isContextLost()) { GrContext* grCtx = m_contextProvider->grContext(); RefPtr<SkSurface> surface(createSkSurface(grCtx, m_size, m_msaaSampleCount, m_opacityMode)); if (surface.get()) { m_surface = surface.release(); m_initialSurfaceSaveCount = m_surface->getCanvas()->getSaveCount(); // FIXME: draw sad canvas picture into new buffer crbug.com/243842 } } return m_surface; }
bool Canvas2DLayerBridge::restoreSurface() { ASSERT(!m_destructionInProgress); if (m_destructionInProgress) return false; ASSERT(m_layer && !m_isSurfaceValid); WebGraphicsContext3D* sharedContext = 0; m_layer->clearTexture(); m_contextProvider = adoptPtr(Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); if (m_contextProvider) sharedContext = m_contextProvider->context3d(); if (sharedContext && !sharedContext->isContextLost()) { SkISize skSize = m_canvas->getBaseLayerSize(); IntSize size(skSize.width(), skSize.height()); RefPtr<SkSurface> surface(createSkSurface(m_contextProvider->grContext(), size, m_msaaSampleCount, m_opacityMode)); if (surface.get()) { m_surface = surface.release(); m_canvas->setSurface(m_surface.get()); m_isSurfaceValid = true; // FIXME: draw sad canvas picture into new buffer crbug.com/243842 } } return m_isSurfaceValid; }
void Canvas2DLayerBridge::flushGpu() { TRACE_EVENT0("cc", "Canvas2DLayerBridge::flushGpu"); flush(); WebGraphicsContext3D* webContext = context(); if (isAccelerated() && webContext) webContext->flush(); }
void WebGLProgram::cacheInfoIfNeeded() { if (m_infoValid) return; if (!m_object) return; if (!contextGroup()) return; WebGraphicsContext3D* context = contextGroup()->getAWebGraphicsContext3D(); if (!context) return; GLint linkStatus = 0; context->getProgramiv(m_object, GL_LINK_STATUS, &linkStatus); m_linkStatus = linkStatus; if (m_linkStatus) cacheActiveAttribLocations(context); m_infoValid = true; }
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) { ASSERT(isAccelerated()); 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. skipQueuedDrawCommands(); m_lastImageId = 0; return false; } if (!checkSurfaceValid()) return false; WebGraphicsContext3D* webContext = context(); RefPtr<SkImage> image = newImageSnapshot(PreferAcceleration); // Early exit if canvas was not drawn to since last prepareMailbox GLenum filter = m_filterQuality == kNone_SkFilterQuality ? 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. // Need to flush skia's internal queue because texture is about to be accessed directly grContext->flush(); 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> mailboxNameData = adoptRef(SkData::NewWithCopy(&mailboxInfo.m_mailbox.name[0], sizeof(mailboxInfo.m_mailbox.name))); image->getTexture()->setCustomData(mailboxNameData.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 { // FIXME: We'd rather insert a syncpoint than perform a flush here, // but currentlythe canvas will flicker if we don't flush here. 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; }
// static bool WebGLDrawBuffers::satisfiesWebGLRequirements(WebGLRenderingContextBase* webglContext) { WebGraphicsContext3D* context = webglContext->webContext(); Extensions3DUtil* extensionsUtil = webglContext->extensionsUtil(); // This is called after we make sure GL_EXT_draw_buffers is supported. GLint maxDrawBuffers = 0; GLint maxColorAttachments = 0; context->getIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers); context->getIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &maxColorAttachments); if (maxDrawBuffers < 4 || maxColorAttachments < 4) return false; Platform3DObject fbo = context->createFramebuffer(); context->bindFramebuffer(GL_FRAMEBUFFER, fbo); const unsigned char* buffer = 0; // Chromium doesn't allow init data for depth/stencil tetxures. bool supportsDepth = (extensionsUtil->supportsExtension("GL_CHROMIUM_depth_texture") || extensionsUtil->supportsExtension("GL_OES_depth_texture") || extensionsUtil->supportsExtension("GL_ARB_depth_texture")); bool supportsDepthStencil = (extensionsUtil->supportsExtension("GL_EXT_packed_depth_stencil") || extensionsUtil->supportsExtension("GL_OES_packed_depth_stencil")); Platform3DObject depthStencil = 0; if (supportsDepthStencil) { depthStencil = context->createTexture(); context->bindTexture(GL_TEXTURE_2D, depthStencil); context->texImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_STENCIL_OES, 1, 1, 0, GL_DEPTH_STENCIL_OES, GL_UNSIGNED_INT_24_8_OES, buffer); } Platform3DObject depth = 0; if (supportsDepth) { depth = context->createTexture(); context->bindTexture(GL_TEXTURE_2D, depth); context->texImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 1, 1, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buffer); } Vector<Platform3DObject> colors; bool ok = true; GLint maxAllowedBuffers = std::min(maxDrawBuffers, maxColorAttachments); for (GLint i = 0; i < maxAllowedBuffers; ++i) { Platform3DObject color = context->createTexture(); colors.append(color); context->bindTexture(GL_TEXTURE_2D, color); context->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, color, 0); if (context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { ok = false; break; } if (supportsDepth) { context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0); if (context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { ok = false; break; } context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); } if (supportsDepthStencil) { context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthStencil, 0); context->framebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthStencil, 0); if (context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { ok = false; break; } context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); context->framebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); } } webglContext->restoreCurrentFramebuffer(); context->deleteFramebuffer(fbo); webglContext->restoreCurrentTexture2D(); if (supportsDepth) context->deleteTexture(depth); if (supportsDepthStencil) context->deleteTexture(depthStencil); for (size_t i = 0; i < colors.size(); ++i) context->deleteTexture(colors[i]); return ok; }