| Index: src/gpu/GrDrawTarget.cpp
|
| ===================================================================
|
| --- src/gpu/GrDrawTarget.cpp (revision 8508)
|
| +++ src/gpu/GrDrawTarget.cpp (working copy)
|
| @@ -412,8 +412,7 @@
|
| }
|
| GrRenderTarget* rt = this->drawState()->getRenderTarget();
|
| // If the dst is not a texture then we don't currently have a way of copying the
|
| - // texture. TODO: make copying RT->Tex (or Surface->Surface) a GrDrawTarget operation that can
|
| - // be built on top of GL/D3D APIs.
|
| + // texture. TODO: API-specific impl of onCopySurface that can handle more cases.
|
| if (NULL == rt->asTexture()) {
|
| GrPrintf("Reading Dst of non-texture render target is not currently supported.\n");
|
| return false;
|
| @@ -436,8 +435,6 @@
|
| #endif
|
| }
|
|
|
| - GrDrawTarget::AutoGeometryAndStatePush agasp(this, kReset_ASRInit);
|
| -
|
| // The draw will resolve dst if it has MSAA. Two things to consider in the future:
|
| // 1) to make the dst values be pre-resolve we'd need to be able to copy to MSAA
|
| // texture and sample it correctly in the shader. 2) If 1 isn't available then we
|
| @@ -456,21 +453,14 @@
|
| GrPrintf("Failed to create temporary copy of destination texture.\n");
|
| return false;
|
| }
|
| - this->drawState()->disableState(GrDrawState::kClip_StateBit);
|
| - this->drawState()->setRenderTarget(ast.texture()->asRenderTarget());
|
| - static const int kTextureStage = 0;
|
| - SkMatrix matrix;
|
| - matrix.setIDiv(rt->width(), rt->height());
|
| - this->drawState()->createTextureEffect(kTextureStage, rt->asTexture(), matrix);
|
| -
|
| - SkRect srcRect = SkRect::MakeFromIRect(copyRect);
|
| - SkRect dstRect = SkRect::MakeWH(SkIntToScalar(copyRect.width()),
|
| - SkIntToScalar(copyRect.height()));
|
| - this->drawRect(dstRect, NULL, &srcRect, NULL);
|
| -
|
| - info->fDstCopy.setTexture(ast.texture());
|
| - info->fDstCopy.setOffset(copyRect.fLeft, copyRect.fTop);
|
| - return true;
|
| + SkIPoint dstPoint = {0, 0};
|
| + if (this->copySurface(ast.texture(), rt, copyRect, dstPoint)) {
|
| + info->fDstCopy.setTexture(ast.texture());
|
| + info->fDstCopy.setOffset(copyRect.fLeft, copyRect.fTop);
|
| + return true;
|
| + } else {
|
| + return false;
|
| + }
|
| }
|
|
|
| void GrDrawTarget::drawIndexed(GrPrimitiveType type,
|
| @@ -761,6 +751,100 @@
|
| target->setClip(&fReplacementClip);
|
| }
|
|
|
| +bool GrDrawTarget::copySurface(GrSurface* dst,
|
| + GrSurface* src,
|
| + const SkIRect& srcRect,
|
| + const SkIPoint& dstPoint) {
|
| + SkIRect clippedSrcRect(srcRect);
|
| + SkIPoint clippedDstPoint(dstPoint);
|
| +
|
| + // clip the left edge to src and dst bounds, adjusting dstPoint if neceessary
|
| + if (clippedSrcRect.fLeft < 0) {
|
| + clippedDstPoint.fX -= clippedSrcRect.fLeft;
|
| + clippedSrcRect.fLeft = 0;
|
| + }
|
| + if (clippedDstPoint.fX < 0) {
|
| + clippedSrcRect.fLeft -= clippedDstPoint.fX;
|
| + clippedDstPoint.fX = 0;
|
| + }
|
| +
|
| + // clip the top edge to src and dst bounds, adjusting dstPoint if neceessary
|
| + if (clippedSrcRect.fTop < 0) {
|
| + clippedDstPoint.fY -= clippedSrcRect.fTop;
|
| + clippedSrcRect.fTop = 0;
|
| + }
|
| + if (clippedDstPoint.fY < 0) {
|
| + clippedSrcRect.fTop -= clippedDstPoint.fY;
|
| + clippedDstPoint.fY = 0;
|
| + }
|
| +
|
| + // clip the right edge to the src and dst bounds.
|
| + if (clippedSrcRect.fRight > src->width()) {
|
| + clippedSrcRect.fRight = src->width();
|
| + }
|
| + if (clippedDstPoint.fX + clippedSrcRect.width() > dst->width()) {
|
| + clippedSrcRect.fRight = clippedSrcRect.fLeft + dst->width() - clippedDstPoint.fX;
|
| + }
|
| +
|
| + // clip the bottom edge to the src and dst bounds.
|
| + if (clippedSrcRect.fBottom > src->height()) {
|
| + clippedSrcRect.fBottom = src->height();
|
| + }
|
| + if (clippedDstPoint.fY + clippedSrcRect.height() > dst->height()) {
|
| + clippedSrcRect.fBottom = clippedSrcRect.fTop + dst->height() - clippedDstPoint.fY;
|
| + }
|
| +
|
| + // The above clipping steps may have inverted the rect if it didn't intersect either the src or
|
| + // dst bounds.
|
| + if (clippedSrcRect.isEmpty()) {
|
| + return true;
|
| + }
|
| +
|
| + bool result = this->onCopySurface(dst, src, clippedSrcRect, clippedDstPoint);
|
| + GrAssert(result == this->canCopySurface(dst, src, clippedSrcRect, clippedDstPoint));
|
| + return result;
|
| +}
|
| +
|
| +bool GrDrawTarget::canCopySurface(GrSurface* dst,
|
| + GrSurface* src,
|
| + const SkIRect& srcRect,
|
| + const SkIPoint& dstPoint) {
|
| + // Check that the read/write rects are contained within the src/dst bounds.
|
| + GrAssert(!srcRect.isEmpty());
|
| + GrAssert(SkIRect::MakeWH(src->width(), src->height()).contains(srcRect));
|
| + GrAssert(dstPoint.fX >= 0 && dstPoint.fY >= 0);
|
| + GrAssert(dstPoint.fX + srcRect.width() <= dst->width() &&
|
| + dstPoint.fY + srcRect.height() <= dst->height());
|
| +
|
| + return NULL != dst->asRenderTarget() && NULL != src->asTexture();
|
| +}
|
| +
|
| +bool GrDrawTarget::onCopySurface(GrSurface* dst,
|
| + GrSurface* src,
|
| + const SkIRect& srcRect,
|
| + const SkIPoint& dstPoint) {
|
| + if (!GrDrawTarget::canCopySurface(dst, src, srcRect, dstPoint)) {
|
| + return false;
|
| + }
|
| +
|
| + GrRenderTarget* rt = dst->asRenderTarget();
|
| + GrTexture* tex = src->asTexture();
|
| +
|
| + GrDrawTarget::AutoStateRestore asr(this, kReset_ASRInit);
|
| + this->drawState()->setRenderTarget(rt);
|
| + SkMatrix matrix;
|
| + matrix.setTranslate(SkIntToScalar(srcRect.fLeft - dstPoint.fX),
|
| + SkIntToScalar(srcRect.fTop - dstPoint.fY));
|
| + matrix.postIDiv(tex->width(), tex->height());
|
| + this->drawState()->createTextureEffect(0, tex, matrix);
|
| + SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX,
|
| + dstPoint.fY,
|
| + srcRect.width(),
|
| + srcRect.height());
|
| + this->drawSimpleRect(dstRect);
|
| + return true;
|
| +}
|
| +
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| SK_DEFINE_INST_COUNT(GrDrawTargetCaps)
|
|
|