sk_sp<SkImage> SkSurface_Gpu::onNewImageSnapshot(SkBudgeted budgeted, ForceCopyMode forceCopyMode) { GrRenderTarget* rt = fDevice->accessDrawContext()->accessRenderTarget(); SkASSERT(rt); GrTexture* tex = rt->asTexture(); SkAutoTUnref<GrTexture> copy; // If the original render target is a buffer originally created by the client, then we don't // want to ever retarget the SkSurface at another buffer we create. Force a copy now to avoid // copy-on-write. if (kYes_ForceCopyMode == forceCopyMode || !tex || rt->resourcePriv().refsWrappedObjects()) { GrSurfaceDesc desc = fDevice->accessDrawContext()->desc(); GrContext* ctx = fDevice->context(); desc.fFlags = desc.fFlags & ~kRenderTarget_GrSurfaceFlag; copy.reset(ctx->textureProvider()->createTexture(desc, budgeted)); if (!copy) { return nullptr; } if (!ctx->copySurface(copy, rt)) { return nullptr; } tex = copy; } const SkImageInfo info = fDevice->imageInfo(); sk_sp<SkImage> image; if (tex) { image = sk_make_sp<SkImage_Gpu>(info.width(), info.height(), kNeedNewImageUniqueID, info.alphaType(), tex, sk_ref_sp(info.colorSpace()), budgeted); } return image; }
Canvas2DLayerBridge::Canvas2DLayerBridge(PassRefPtr<GraphicsContext3D> context, SkDeferredCanvas* canvas, OpacityMode opacityMode, ThreadMode threadMode) : m_canvas(canvas) , m_context(context) , m_bytesAllocated(0) , m_didRecordDrawCommand(false) , m_framesPending(0) , m_next(0) , m_prev(0) #if ENABLE(CANVAS_USES_MAILBOX) , m_lastImageId(0) #endif { ASSERT(m_canvas); // Used by browser tests to detect the use of a Canvas2DLayerBridge. TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation"); m_canvas->setNotificationClient(this); #if ENABLE(CANVAS_USES_MAILBOX) m_layer = adoptPtr(WebKit::Platform::current()->compositorSupport()->createExternalTextureLayerForMailbox(this)); #else m_layer = adoptPtr(WebKit::Platform::current()->compositorSupport()->createExternalTextureLayer(this)); m_layer->setRateLimitContext(threadMode == SingleThread); GrRenderTarget* renderTarget = reinterpret_cast<GrRenderTarget*>(m_canvas->getDevice()->accessRenderTarget()); if (renderTarget) { m_layer->setTextureId(renderTarget->asTexture()->getTextureHandle()); } #endif m_layer->setOpaque(opacityMode == Opaque); GraphicsLayerChromium::registerContentsLayer(m_layer->layer()); }
SkImage* SkSurface_Gpu::onNewImageSnapshot(SkBudgeted budgeted, ForceCopyMode forceCopyMode) { GrRenderTarget* rt = fDevice->accessRenderTarget(); SkASSERT(rt); GrTexture* tex = rt->asTexture(); SkAutoTUnref<GrTexture> copy; // TODO: Force a copy when the rt is an external resource. if (kYes_ForceCopyMode == forceCopyMode || !tex) { GrSurfaceDesc desc = fDevice->accessRenderTarget()->desc(); GrContext* ctx = fDevice->context(); desc.fFlags = desc.fFlags & ~kRenderTarget_GrSurfaceFlag; copy.reset(ctx->textureProvider()->createTexture(desc, budgeted)); if (!copy) { return nullptr; } if (!ctx->copySurface(copy, rt)) { return nullptr; } tex = copy; } const SkImageInfo info = fDevice->imageInfo(); SkImage* image = nullptr; if (tex) { image = new SkImage_Gpu(info.width(), info.height(), kNeedNewImageUniqueID, info.alphaType(), tex, budgeted); } return image; }
Platform3DObject AcceleratedImageBufferSurface::getBackingTexture() const { GrRenderTarget* renderTarget = m_canvas->getTopDevice()->accessRenderTarget(); if (renderTarget) { return renderTarget->asTexture()->getTextureHandle(); } return 0; }
GrBackendObject SkSurface_Gpu::onGetTextureHandle(BackendHandleAccess access) { GrRenderTarget* rt = prepare_rt_for_external_access(this, access); GrTexture* texture = rt->asTexture(); if (texture) { return texture->getTextureHandle(); } return 0; }
unsigned Canvas2DLayerBridge::backBufferTexture() { contextAcquired(); m_canvas->flush(); m_context->flush(); GrRenderTarget* renderTarget = reinterpret_cast<GrRenderTarget*>(m_canvas->getDevice()->accessRenderTarget()); if (renderTarget) { return renderTarget->asTexture()->getTextureHandle(); } return 0; }
// Create a new render target and, if necessary, copy the contents of the old // render target into it. Note that this flushes the SkGpuDevice but // doesn't force an OpenGL flush. void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) { GrRenderTarget* rt = fDevice->accessDrawContext()->accessRenderTarget(); // are we sharing our render target with the image? Note this call should never create a new // image because onCopyOnWrite is only called when there is a cached image. sk_sp<SkImage> image(this->refCachedImage(SkBudgeted::kNo, kNo_ForceUnique)); SkASSERT(image); if (rt->asTexture() == as_IB(image)->peekTexture()) { this->fDevice->replaceDrawContext(SkSurface::kRetain_ContentChangeMode == mode); SkTextureImageApplyBudgetedDecision(image.get()); } else if (kDiscard_ContentChangeMode == mode) { this->SkSurface_Gpu::onDiscard(); } }
// Create a new render target and, if necessary, copy the contents of the old // render target into it. Note that this flushes the SkGpuDevice but // doesn't force an OpenGL flush. void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) { GrRenderTarget* rt = fDevice->accessRenderTarget(); // are we sharing our render target with the image? Note this call should never create a new // image because onCopyOnWrite is only called when there is a cached image. SkImage* image = this->getCachedImage(kNo_Budgeted); SkASSERT(image); if (rt->asTexture() == SkTextureImageGetTexture(image)) { this->fDevice->replaceRenderTarget(SkSurface::kRetain_ContentChangeMode == mode); SkTextureImageApplyBudgetedDecision(image); } else if (kDiscard_ContentChangeMode == mode) { this->SkSurface_Gpu::onDiscard(); } }
Platform3DObject Canvas2DLayerBridge::getBackingTexture() { ASSERT(!m_destructionInProgress); if (!checkSurfaceValid()) return 0; m_canvas->flush(); context()->flush(); GrRenderTarget* renderTarget = m_canvas->getTopDevice()->accessRenderTarget(); if (renderTarget) { return renderTarget->asTexture()->getTextureHandle(); } return 0; }
unsigned Canvas2DLayerBridge::prepareTexture(WebTextureUpdater& updater) { #if ENABLE(CANVAS_USES_MAILBOX) ASSERT_NOT_REACHED(); return 0; #else m_context->makeContextCurrent(); TRACE_EVENT0("cc", "Canvas2DLayerBridge::SkCanvas::flush"); m_canvas->flush(); m_context->flush(); // Notify skia that the state of the backing store texture object will be touched by the compositor GrRenderTarget* renderTarget = reinterpret_cast<GrRenderTarget*>(m_canvas->getDevice()->accessRenderTarget()); if (renderTarget) { GrTexture* texture = renderTarget->asTexture(); texture->invalidateCachedState(); return texture->getTextureHandle(); } return 0; #endif // !ENABLE(CANVAS_USES_MAILBOX) }
unsigned Canvas2DLayerBridge::prepareTexture(WebTextureUpdater& updater) { m_context->makeContextCurrent(); if (m_canvas) { TRACE_EVENT0("cc", "Canvas2DLayerBridge::SkCanvas::flush"); m_canvas->flush(); } m_context->flush(); if (m_useDoubleBuffering) { updater.appendCopy(m_backBufferTexture, m_frontBufferTexture, m_size); return m_frontBufferTexture; } if (m_canvas) { // Notify skia that the state of the backing store texture object will be touched by the compositor GrRenderTarget* renderTarget = reinterpret_cast<GrRenderTarget*>(m_canvas->getDevice()->accessRenderTarget()); if (renderTarget) renderTarget->asTexture()->invalidateCachedState(); } return m_backBufferTexture; }
bool GrDrawTarget::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuilder, const GrPipelineOptimizations& optimizations, GrXferProcessor::DstTexture* dstTexture, const SkRect& batchBounds) { SkRect bounds = batchBounds; bounds.outset(0.5f, 0.5f); if (!pipelineBuilder.willXPNeedDstTexture(*this->caps(), optimizations)) { return true; } GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); if (this->caps()->textureBarrierSupport()) { if (GrTexture* rtTex = rt->asTexture()) { // The render target is a texture, so we can read from it directly in the shader. The XP // will be responsible to detect this situation and request a texture barrier. dstTexture->setTexture(rtTex); dstTexture->setOffset(0, 0); return true; } } SkIRect copyRect; pipelineBuilder.clip().getConservativeBounds(rt->width(), rt->height(), ©Rect); SkIRect drawIBounds; bounds.roundOut(&drawIBounds); if (!copyRect.intersect(drawIBounds)) { #ifdef SK_DEBUG GrCapsDebugf(this->caps(), "Missed an early reject. " "Bailing on draw from setupDstReadIfNecessary.\n"); #endif return false; } // MSAA consideration: When there is support for reading MSAA samples in the shader we could // have per-sample dst values by making the copy multisampled. GrSurfaceDesc desc; if (!fGpu->initCopySurfaceDstDesc(rt, &desc)) { desc.fOrigin = kDefault_GrSurfaceOrigin; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fConfig = rt->config(); } desc.fWidth = copyRect.width(); desc.fHeight = copyRect.height(); static const uint32_t kFlags = 0; SkAutoTUnref<GrTexture> copy(fResourceProvider->createApproxTexture(desc, kFlags)); if (!copy) { SkDebugf("Failed to create temporary copy of destination texture.\n"); return false; } SkIPoint dstPoint = {0, 0}; this->copySurface(copy, rt, copyRect, dstPoint); dstTexture->setTexture(copy); dstTexture->setOffset(copyRect.fLeft, copyRect.fTop); return true; }