aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/SkGpuDevice_drawTexture.cpp
diff options
context:
space:
mode:
authorGravatar bsalomon <bsalomon@google.com>2015-11-09 11:55:57 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2015-11-09 11:55:57 -0800
commitc55271f2551533b37043aa2e37f754832a43073c (patch)
tree5e9729a4c8fe05519805b97db38621efbc34956a /src/gpu/SkGpuDevice_drawTexture.cpp
parent3a210bfd403815bebbc7efabe7bbd373e5a3d8f8 (diff)
Separate out natively-texture image/bmp draws from cached-as-texture image/bmp draws
This makes texture-backed images and bitmaps down a new code path. It adds a pinch point via the texture adjuster that will be used to handle copied necessary for different texture targets. It also fixes bugs in the existing code exhibited by recent updates to the bleed GM. The plan is to move the the sw/generator-backed imgs/bmps on to this code path with future changes. Review URL: https://codereview.chromium.org/1424313010
Diffstat (limited to 'src/gpu/SkGpuDevice_drawTexture.cpp')
-rw-r--r--src/gpu/SkGpuDevice_drawTexture.cpp204
1 files changed, 204 insertions, 0 deletions
diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp
new file mode 100644
index 0000000000..902aae0843
--- /dev/null
+++ b/src/gpu/SkGpuDevice_drawTexture.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkGpuDevice.h"
+
+#include "GrBlurUtils.h"
+#include "GrCaps.h"
+#include "GrDrawContext.h"
+#include "GrStrokeInfo.h"
+#include "GrTextureParamsAdjuster.h"
+#include "SkDraw.h"
+#include "SkGrPriv.h"
+#include "SkMaskFilter.h"
+#include "effects/GrBicubicEffect.h"
+#include "effects/GrSimpleTextureEffect.h"
+#include "effects/GrTextureDomain.h"
+
+static inline bool use_shader(bool textureIsAlphaOnly, const SkPaint& paint) {
+ return textureIsAlphaOnly && paint.getShader();
+}
+
+/** Determines how to combine the texture FP with the paint's color and SkShader, if any. */
+static const GrFragmentProcessor* mix_texture_fp_with_paint_color_and_shader(
+ const GrFragmentProcessor* textureFP,
+ bool textureIsAlphaOnly,
+ GrContext* context,
+ const SkMatrix& viewMatrix,
+ const SkPaint& paint) {
+ // According to the SkCanvas API, we only consider the shader if the bitmap or image being
+ // rendered is alpha-only.
+ if (textureIsAlphaOnly) {
+ if (const SkShader* shader = paint.getShader()) {
+ SkAutoTUnref<const GrFragmentProcessor> shaderFP(
+ shader->asFragmentProcessor(context,
+ viewMatrix,
+ nullptr,
+ paint.getFilterQuality()));
+ if (!shaderFP) {
+ return nullptr;
+ }
+ const GrFragmentProcessor* fpSeries[] = { shaderFP, textureFP };
+ return GrFragmentProcessor::RunInSeries(fpSeries, 2);
+ } else {
+ return GrFragmentProcessor::MulOutputByInputUnpremulColor(textureFP);
+ }
+ } else {
+ return GrFragmentProcessor::MulOutputByInputAlpha(textureFP);
+ }
+}
+
+void SkGpuDevice::drawTextureAdjuster(GrTextureAdjuster* adjuster,
+ bool alphaOnly,
+ const SkRect* srcRect,
+ const SkRect* dstRect,
+ SkCanvas::SrcRectConstraint constraint,
+ const SkMatrix& viewMatrix,
+ const GrClip& clip,
+ const SkPaint& paint) {
+ // Figure out the actual dst and src rect by clipping the src rect to the bounds of the
+ // adjuster. If the src rect is clipped then the dst rect must be recomputed. Also determine
+ // the matrix that maps the src rect to the dst rect.
+ SkRect clippedSrcRect;
+ SkRect clippedDstRect;
+ SkIRect contentIBounds;
+ adjuster->getContentArea(&contentIBounds);
+ const SkRect contentBounds = SkRect::Make(contentIBounds);
+ SkMatrix srcToDstMatrix;
+ if (srcRect) {
+ if (!dstRect) {
+ dstRect = &contentBounds;
+ }
+ if (!contentBounds.contains(*srcRect)) {
+ clippedSrcRect = *srcRect;
+ if (!clippedSrcRect.intersect(contentBounds)) {
+ return;
+ }
+ if (!srcToDstMatrix.setRectToRect(*srcRect, *dstRect, SkMatrix::kFill_ScaleToFit)) {
+ return;
+ }
+ srcToDstMatrix.mapRect(&clippedDstRect, clippedSrcRect);
+ } else {
+ clippedSrcRect = *srcRect;
+ clippedDstRect = *dstRect;
+ if (!srcToDstMatrix.setRectToRect(*srcRect, *dstRect, SkMatrix::kFill_ScaleToFit)) {
+ return;
+ }
+ }
+ } else {
+ clippedSrcRect = contentBounds;
+ if (dstRect) {
+ clippedDstRect = *dstRect;
+ if (!srcToDstMatrix.setRectToRect(contentBounds, *dstRect,
+ SkMatrix::kFill_ScaleToFit)) {
+ return;
+ }
+ } else {
+ clippedDstRect = contentBounds;
+ srcToDstMatrix.reset();
+ }
+ }
+
+ this->drawTextureAdjusterImpl(adjuster, alphaOnly, clippedSrcRect, clippedDstRect, constraint,
+ viewMatrix, srcToDstMatrix, clip, paint);
+}
+
+void SkGpuDevice::drawTextureAdjusterImpl(GrTextureAdjuster* adjuster,
+ bool alphaTexture,
+ const SkRect& clippedSrcRect,
+ const SkRect& clippedDstRect,
+ SkCanvas::SrcRectConstraint constraint,
+ const SkMatrix& viewMatrix,
+ const SkMatrix& srcToDstMatrix,
+ const GrClip& clip,
+ const SkPaint& paint) {
+ // Specifying the texture coords as local coordinates is an attempt to enable more batching
+ // by not baking anything about the srcRect, dstRect, or viewMatrix, into the texture FP. In
+ // the future this should be an opaque optimization enabled by the combination of batch/GP and
+ // FP.
+ const SkMatrix* textureFPMatrix;
+ SkMatrix tempMatrix;
+ const SkMaskFilter* mf = paint.getMaskFilter();
+ GrTexture* texture = adjuster->originalTexture();
+ // The shader expects proper local coords, so we can't replace local coords with texture coords
+ // if the shader will be used. If we have a mask filter we will change the underlying geometry
+ // that is rendered.
+ bool canUseTextureCoordsAsLocalCoords = !use_shader(alphaTexture, paint) && !mf;
+ if (canUseTextureCoordsAsLocalCoords) {
+ textureFPMatrix = &SkMatrix::I();
+ } else {
+ if (!srcToDstMatrix.invert(&tempMatrix)) {
+ return;
+ }
+ tempMatrix.postIDiv(texture->width(), texture->height());
+ textureFPMatrix = &tempMatrix;
+ }
+
+ bool doBicubic;
+ GrTextureParams::FilterMode fm =
+ GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewMatrix, srcToDstMatrix,
+ &doBicubic);
+ const GrTextureParams::FilterMode* filterMode = doBicubic ? nullptr : &fm;
+
+ GrTextureAdjuster::FilterConstraint constraintMode;
+ if (SkCanvas::kFast_SrcRectConstraint == constraint) {
+ constraintMode = GrTextureAdjuster::kNo_FilterConstraint;
+ } else {
+ constraintMode = GrTextureAdjuster::kYes_FilterConstraint;
+ }
+
+ // If we have to outset for AA then we will generate texture coords outside the src rect. The
+ // same happens for any mask filter that extends the bounds rendered in the dst.
+ // This is conservative as a mask filter does not have to expand the bounds rendered.
+ bool coordsAllInsideSrcRect = !paint.isAntiAlias() && !mf;
+
+ SkAutoTUnref<const GrFragmentProcessor> fp(adjuster->createFragmentProcessor(
+ *textureFPMatrix, clippedSrcRect, constraintMode, coordsAllInsideSrcRect, filterMode));
+ if (!fp) {
+ return;
+ }
+ fp.reset(mix_texture_fp_with_paint_color_and_shader(fp, alphaTexture, this->context(),
+ viewMatrix, paint));
+ GrPaint grPaint;
+ if (!SkPaintToGrPaintReplaceShader(fContext, paint, fp, &grPaint)) {
+ return;
+ }
+
+ if (canUseTextureCoordsAsLocalCoords) {
+ SkRect localRect;
+ localRect.fLeft = clippedSrcRect.fLeft / texture->width();
+ localRect.fBottom = clippedSrcRect.fBottom / texture->height();
+ localRect.fRight = clippedSrcRect.fRight / texture->width();
+ localRect.fTop = clippedSrcRect.fTop / texture->height();
+ fDrawContext->fillRectToRect(clip, grPaint, viewMatrix, clippedDstRect, localRect);
+ return;
+ }
+
+ if (!mf) {
+ fDrawContext->drawRect(clip, grPaint, viewMatrix, clippedDstRect);
+ return;
+ }
+
+ // First see if we can do the draw + mask filter direct to the dst.
+ SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
+ SkRRect rrect;
+ rrect.setRect(clippedDstRect);
+ if (mf->directFilterRRectMaskGPU(fContext->textureProvider(),
+ fDrawContext,
+ &grPaint,
+ clip,
+ viewMatrix,
+ rec,
+ rrect)) {
+ return;
+ }
+ SkPath rectPath;
+ rectPath.addRect(clippedDstRect);
+ GrBlurUtils::drawPathWithMaskFilter(this->context(), fDrawContext, fRenderTarget, fClip,
+ rectPath, &grPaint, viewMatrix, mf, paint.getPathEffect(),
+ GrStrokeInfo::FillInfo());
+}