blob: f7e518be9795f92792ec3971d101f771ae29d13b [file] [log] [blame]
robertphillips@google.com58b20212012-06-27 20:44:52 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrSWMaskHelper.h"
krajcevski5c2fca02014-06-10 17:25:28 -07009
bsalomoneb1cb5c2015-05-22 08:01:09 -070010#include "GrCaps.h"
robertphillips976f5f02016-06-03 10:59:20 -070011#include "GrContext.h"
Robert Phillipse305cc1f2016-12-14 12:19:05 -050012#include "GrContextPriv.h"
bsalomonbb243832016-07-22 07:10:19 -070013#include "GrPipelineBuilder.h"
Brian Salomon89527432016-12-16 09:52:16 -050014#include "GrRenderTargetContext.h"
bsalomon8acedde2016-06-24 10:42:16 -070015#include "GrShape.h"
Robert Phillipse305cc1f2016-12-14 12:19:05 -050016#include "GrSurfaceContext.h"
17#include "GrTextureProxy.h"
Brian Salomon89527432016-12-16 09:52:16 -050018#include "ops/GrDrawOp.h"
robertphillips@google.com58b20212012-06-27 20:44:52 +000019
jvanverthfa38a302014-10-06 05:59:05 -070020#include "SkDistanceFieldGen.h"
sugoi@google.com12b4e272012-12-06 20:13:11 +000021
Brian Salomon89527432016-12-16 09:52:16 -050022#include "ops/GrRectOpFactory.h"
robertphillips@google.com58b20212012-06-27 20:44:52 +000023
robertphillips@google.com58b20212012-06-27 20:44:52 +000024/*
25 * Convert a boolean operation into a transfer mode code
26 */
reed374772b2016-10-05 17:33:02 -070027static SkBlendMode op_to_mode(SkRegion::Op op) {
robertphillips@google.com58b20212012-06-27 20:44:52 +000028
reed374772b2016-10-05 17:33:02 -070029 static const SkBlendMode modeMap[] = {
30 SkBlendMode::kDstOut, // kDifference_Op
31 SkBlendMode::kModulate, // kIntersect_Op
32 SkBlendMode::kSrcOver, // kUnion_Op
33 SkBlendMode::kXor, // kXOR_Op
34 SkBlendMode::kClear, // kReverseDifference_Op
35 SkBlendMode::kSrc, // kReplace_Op
robertphillips@google.com58b20212012-06-27 20:44:52 +000036 };
37
38 return modeMap[op];
39}
40
robertphillips@google.com58b20212012-06-27 20:44:52 +000041/**
42 * Draw a single rect element of the clip stack into the accumulation bitmap
43 */
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050044void GrSWMaskHelper::drawRect(const SkRect& rect, SkRegion::Op op, GrAA aa, uint8_t alpha) {
robertphillips@google.com58b20212012-06-27 20:44:52 +000045 SkPaint paint;
46
reed374772b2016-10-05 17:33:02 -070047 paint.setBlendMode(op_to_mode(op));
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050048 paint.setAntiAlias(GrAA::kYes == aa);
robertphillips@google.com366f1c62012-06-29 21:38:47 +000049 paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
robertphillips@google.com58b20212012-06-27 20:44:52 +000050
robertphillips@google.com366f1c62012-06-29 21:38:47 +000051 fDraw.drawRect(rect, paint);
robertphillips@google.com58b20212012-06-27 20:44:52 +000052}
53
54/**
55 * Draw a single path element of the clip stack into the accumulation bitmap
56 */
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050057void GrSWMaskHelper::drawShape(const GrShape& shape, SkRegion::Op op, GrAA aa, uint8_t alpha) {
robertphillips@google.com58b20212012-06-27 20:44:52 +000058 SkPaint paint;
Robert Phillipsf809c1e2017-01-13 11:02:42 -050059 paint.setPathEffect(shape.style().refPathEffect());
bsalomon8acedde2016-06-24 10:42:16 -070060 shape.style().strokeRec().applyToPaint(&paint);
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050061 paint.setAntiAlias(GrAA::kYes == aa);
reed@google.com84e922b2013-11-04 20:57:36 +000062
bsalomon8acedde2016-06-24 10:42:16 -070063 SkPath path;
64 shape.asPath(&path);
reed@google.com126f7f52013-11-07 16:06:53 +000065 if (SkRegion::kReplace_Op == op && 0xFF == alpha) {
66 SkASSERT(0xFF == paint.getAlpha());
robertphillips98377402016-05-13 05:47:23 -070067 fDraw.drawPathCoverage(path, paint);
reed@google.com126f7f52013-11-07 16:06:53 +000068 } else {
reed374772b2016-10-05 17:33:02 -070069 paint.setBlendMode(op_to_mode(op));
reed@google.com126f7f52013-11-07 16:06:53 +000070 paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
robertphillips98377402016-05-13 05:47:23 -070071 fDraw.drawPath(path, paint);
reed@google.com126f7f52013-11-07 16:06:53 +000072 }
robertphillips@google.com58b20212012-06-27 20:44:52 +000073}
74
robertphillips98377402016-05-13 05:47:23 -070075bool GrSWMaskHelper::init(const SkIRect& resultBounds, const SkMatrix* matrix) {
bsalomon49f085d2014-09-05 13:34:00 -070076 if (matrix) {
robertphillips@google.com366f1c62012-06-29 21:38:47 +000077 fMatrix = *matrix;
robertphillips@google.com58b20212012-06-27 20:44:52 +000078 } else {
79 fMatrix.setIdentity();
80 }
81
robertphillips@google.com366f1c62012-06-29 21:38:47 +000082 // Now translate so the bound's UL corner is at the origin
robertphillips98377402016-05-13 05:47:23 -070083 fMatrix.postTranslate(-SkIntToScalar(resultBounds.fLeft), -SkIntToScalar(resultBounds.fTop));
84 SkIRect bounds = SkIRect::MakeWH(resultBounds.width(), resultBounds.height());
krajcevski25a67bc2014-07-29 11:44:26 -070085
robertphillips98377402016-05-13 05:47:23 -070086 const SkImageInfo bmImageInfo = SkImageInfo::MakeA8(bounds.width(), bounds.height());
87 if (!fPixels.tryAlloc(bmImageInfo)) {
88 return false;
krajcevskib8ccc2f2014-08-07 08:15:14 -070089 }
robertphillips98377402016-05-13 05:47:23 -070090 fPixels.erase(0);
krajcevskib8ccc2f2014-08-07 08:15:14 -070091
reed41e010c2015-06-09 12:16:53 -070092 sk_bzero(&fDraw, sizeof(fDraw));
reed41e010c2015-06-09 12:16:53 -070093 fDraw.fDst = fPixels;
robertphillips@google.com58b20212012-06-27 20:44:52 +000094 fRasterClip.setRect(bounds);
reed41e010c2015-06-09 12:16:53 -070095 fDraw.fRC = &fRasterClip;
reed41e010c2015-06-09 12:16:53 -070096 fDraw.fMatrix = &fMatrix;
robertphillips@google.com58b20212012-06-27 20:44:52 +000097 return true;
98}
99
Robert Phillipse305cc1f2016-12-14 12:19:05 -0500100sk_sp<GrTextureProxy> GrSWMaskHelper::toTexture(GrContext* context, SkBackingFit fit) {
bsalomonf2703d82014-10-28 14:33:06 -0700101 GrSurfaceDesc desc;
reed41e010c2015-06-09 12:16:53 -0700102 desc.fWidth = fPixels.width();
103 desc.fHeight = fPixels.height();
krajcevskib3abe902014-07-30 13:08:11 -0700104 desc.fConfig = kAlpha_8_GrPixelConfig;
krajcevskifb4f5cb2014-06-12 09:20:38 -0700105
Robert Phillipse305cc1f2016-12-14 12:19:05 -0500106 sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeDeferredSurfaceContext(
107 desc,
108 fit,
109 SkBudgeted::kYes);
Robert Phillipsf200a902017-01-30 13:27:37 -0500110 if (!sContext || !sContext->asTextureProxy()) {
Robert Phillipse305cc1f2016-12-14 12:19:05 -0500111 return nullptr;
bsalomon39ef7fb2016-09-21 11:16:05 -0700112 }
robertphillips@google.com58b20212012-06-27 20:44:52 +0000113
Robert Phillipsc949ce92017-01-19 16:59:04 -0500114 SkImageInfo ii = SkImageInfo::MakeA8(desc.fWidth, desc.fHeight);
115 if (!sContext->writePixels(ii, fPixels.addr(), fPixels.rowBytes(), 0, 0)) {
Robert Phillipse305cc1f2016-12-14 12:19:05 -0500116 return nullptr;
117 }
cblumeed828002016-02-16 13:00:01 -0800118
Robert Phillipsf200a902017-01-30 13:27:37 -0500119 return sContext->asTextureProxyRef();
robertphillips@google.com58b20212012-06-27 20:44:52 +0000120}
121
jvanverthfa38a302014-10-06 05:59:05 -0700122/**
123 * Convert mask generation results to a signed distance field
124 */
125void GrSWMaskHelper::toSDF(unsigned char* sdf) {
reed41e010c2015-06-09 12:16:53 -0700126 SkGenerateDistanceFieldFromA8Image(sdf, (const unsigned char*)fPixels.addr(),
127 fPixels.width(), fPixels.height(), fPixels.rowBytes());
jvanverthfa38a302014-10-06 05:59:05 -0700128}
129
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000130////////////////////////////////////////////////////////////////////////////////
131/**
bsalomon8acedde2016-06-24 10:42:16 -0700132 * Software rasterizes shape to A8 mask and uploads the result to a scratch texture. Returns the
133 * resulting texture on success; nullptr on failure.
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000134 */
Robert Phillipse305cc1f2016-12-14 12:19:05 -0500135sk_sp<GrTexture> GrSWMaskHelper::DrawShapeMaskToTexture(GrContext* context,
136 const GrShape& shape,
137 const SkIRect& resultBounds,
138 GrAA aa,
139 SkBackingFit fit,
140 const SkMatrix* matrix) {
141 GrSWMaskHelper helper;
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000142
reed@google.com84e922b2013-11-04 20:57:36 +0000143 if (!helper.init(resultBounds, matrix)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700144 return nullptr;
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000145 }
146
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500147 helper.drawShape(shape, SkRegion::kReplace_Op, aa, 0xFF);
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000148
Robert Phillipse305cc1f2016-12-14 12:19:05 -0500149 sk_sp<GrTextureProxy> tProxy = helper.toTexture(context, fit);
150 if (!tProxy) {
halcanary96fcdcc2015-08-27 07:41:13 -0700151 return nullptr;
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000152 }
153
Brian Osman32342f02017-03-04 08:12:46 -0500154 return sk_ref_sp(tProxy->instantiate(context->resourceProvider()));
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000155}
156
bsalomon8acedde2016-06-24 10:42:16 -0700157void GrSWMaskHelper::DrawToTargetWithShapeMask(GrTexture* texture,
Brian Osman11052242016-10-27 14:47:55 -0400158 GrRenderTargetContext* renderTargetContext,
Brian Salomon82f44312017-01-11 13:42:54 -0500159 GrPaint&& paint,
robertphillipsd2b6d642016-07-21 08:55:08 -0700160 const GrUserStencilSettings& userStencilSettings,
bsalomon8acedde2016-06-24 10:42:16 -0700161 const GrClip& clip,
bsalomon8acedde2016-06-24 10:42:16 -0700162 const SkMatrix& viewMatrix,
bsalomon39ef7fb2016-09-21 11:16:05 -0700163 const SkIPoint& textureOriginInDeviceSpace,
164 const SkIRect& deviceSpaceRectToDraw) {
joshualittd27f73e2014-12-29 07:43:36 -0800165 SkMatrix invert;
joshualitt8059eb92014-12-29 15:10:07 -0800166 if (!viewMatrix.invert(&invert)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000167 return;
168 }
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000169
bsalomon39ef7fb2016-09-21 11:16:05 -0700170 SkRect dstRect = SkRect::Make(deviceSpaceRectToDraw);
bsalomon@google.comc7818882013-03-20 19:19:53 +0000171
bsalomon309d4d52014-12-18 10:17:44 -0800172 // We use device coords to compute the texture coordinates. We take the device coords and apply
173 // a translation so that the top-left of the device bounds maps to 0,0, and then a scaling
174 // matrix to normalized coords.
Robert Phillips67c18d62017-01-20 12:44:06 -0500175 SkMatrix maskMatrix = SkMatrix::MakeTrans(SkIntToScalar(-textureOriginInDeviceSpace.fX),
176 SkIntToScalar(-textureOriginInDeviceSpace.fY));
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400177 maskMatrix.preConcat(viewMatrix);
Brian Salomon82f44312017-01-11 13:42:54 -0500178 std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeNonAAFill(paint.getColor(), SkMatrix::I(),
179 dstRect, nullptr, &invert);
Brian Salomond4652ca2017-01-13 12:11:36 -0500180 paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(
181 texture, nullptr, maskMatrix, GrSamplerParams::kNone_FilterMode));
Brian Salomon82f44312017-01-11 13:42:54 -0500182 GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
bsalomonbb243832016-07-22 07:10:19 -0700183 pipelineBuilder.setUserStencil(&userStencilSettings);
Brian Salomon24f19782016-12-13 15:10:11 -0500184 renderTargetContext->addDrawOp(pipelineBuilder, clip, std::move(op));
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000185}