|  | /* | 
|  | * Copyright 2019 Google LLC | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | #include "src/gpu/GrCopyRenderTask.h" | 
|  |  | 
|  | #include "src/gpu/GrGpu.h" | 
|  | #include "src/gpu/GrOpFlushState.h" | 
|  | #include "src/gpu/GrResourceAllocator.h" | 
|  |  | 
|  | sk_sp<GrRenderTask> GrCopyRenderTask::Make(sk_sp<GrSurfaceProxy> srcProxy, | 
|  | const SkIRect& srcRect, | 
|  | sk_sp<GrSurfaceProxy> dstProxy, | 
|  | const SkIPoint& dstPoint, | 
|  | const GrCaps* caps) { | 
|  | SkASSERT(dstProxy); | 
|  | SkASSERT(srcProxy); | 
|  | SkIRect clippedSrcRect; | 
|  | SkIPoint clippedDstPoint; | 
|  | // If the rect is outside the srcProxy or dstProxy then we've already succeeded. | 
|  | if (!GrClipSrcRectAndDstPoint(dstProxy->isize(), srcProxy->isize(), srcRect, dstPoint, | 
|  | &clippedSrcRect, &clippedDstPoint)) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | if (caps->isFormatCompressed(dstProxy->backendFormat())) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | SkASSERT(dstProxy->origin() == srcProxy->origin()); | 
|  | if (srcProxy->origin() == kBottomLeft_GrSurfaceOrigin) { | 
|  | int rectHeight = clippedSrcRect.height(); | 
|  | clippedSrcRect.fTop = srcProxy->height() - clippedSrcRect.fBottom; | 
|  | clippedSrcRect.fBottom = clippedSrcRect.fTop + rectHeight; | 
|  | clippedDstPoint.fY = dstProxy->height() - clippedDstPoint.fY - rectHeight; | 
|  | } | 
|  |  | 
|  | sk_sp<GrCopyRenderTask> task(new GrCopyRenderTask( | 
|  | std::move(srcProxy), clippedSrcRect, std::move(dstProxy), clippedDstPoint)); | 
|  | return task; | 
|  | } | 
|  |  | 
|  | GrCopyRenderTask::GrCopyRenderTask(sk_sp<GrSurfaceProxy> srcProxy, | 
|  | const SkIRect& srcRect, | 
|  | sk_sp<GrSurfaceProxy> dstProxy, | 
|  | const SkIPoint& dstPoint) | 
|  | : GrRenderTask(std::move(dstProxy)) | 
|  | , fSrcProxy(std::move(srcProxy)) | 
|  | , fSrcRect(srcRect) | 
|  | , fDstPoint(dstPoint) { | 
|  | fTarget->setLastRenderTask(this); | 
|  | } | 
|  |  | 
|  | void GrCopyRenderTask::gatherProxyIntervals(GrResourceAllocator* alloc) const { | 
|  | // This renderTask doesn't have "normal" ops. In this case we still need to add an interval (so | 
|  | // fEndOfOpsTaskOpIndices will remain in sync), so we create a fake op# to capture the fact that | 
|  | // we read fSrcProxy and copy to fTarget. | 
|  | alloc->addInterval(fSrcProxy.get(), alloc->curOp(), alloc->curOp(), | 
|  | GrResourceAllocator::ActualUse::kYes); | 
|  | alloc->addInterval(fTarget.get(), alloc->curOp(), alloc->curOp(), | 
|  | GrResourceAllocator::ActualUse::kYes); | 
|  | alloc->incOps(); | 
|  | } | 
|  |  | 
|  | bool GrCopyRenderTask::onExecute(GrOpFlushState* flushState) { | 
|  | if (!fSrcProxy->isInstantiated() || !fTarget->isInstantiated()) { | 
|  | return false; | 
|  | } | 
|  | GrSurface* srcSurface = fSrcProxy->peekSurface(); | 
|  | GrSurface* dstSurface = fTarget->peekSurface(); | 
|  | if (fSrcProxy->origin() == kBottomLeft_GrSurfaceOrigin) { | 
|  | if (fSrcProxy->height() != srcSurface->height()) { | 
|  | fSrcRect.offset(0, srcSurface->height() - fSrcProxy->height()); | 
|  | } | 
|  | if (fTarget->height() != dstSurface->height()) { | 
|  | fDstPoint.fY = fDstPoint.fY + (dstSurface->height() - fTarget->height()); | 
|  | } | 
|  | } | 
|  | return flushState->gpu()->copySurface(dstSurface, srcSurface, fSrcRect, fDstPoint); | 
|  | } | 
|  |  |