blob: b69edab82cab030c7c541d86a9df1a7e3e44439e [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"
kkinnunencabe20c2015-06-01 01:37:26 -070011#include "GrDrawTarget.h"
robertphillips@google.com58b20212012-06-27 20:44:52 +000012#include "GrGpu.h"
joshualitt04194f32016-01-13 10:08:27 -080013#include "GrPipelineBuilder.h"
robertphillips@google.com58b20212012-06-27 20:44:52 +000014
krajcevski5c2fca02014-06-10 17:25:28 -070015#include "SkData.h"
jvanverthfa38a302014-10-06 05:59:05 -070016#include "SkDistanceFieldGen.h"
sugoi@google.com5f74cf82012-12-17 21:16:45 +000017#include "SkStrokeRec.h"
sugoi@google.com12b4e272012-12-06 20:13:11 +000018
joshualitt04194f32016-01-13 10:08:27 -080019#include "batches/GrRectBatchFactory.h"
robertphillips@google.com58b20212012-06-27 20:44:52 +000020
21namespace {
krajcevski5c2fca02014-06-10 17:25:28 -070022
robertphillips@google.com58b20212012-06-27 20:44:52 +000023/*
24 * Convert a boolean operation into a transfer mode code
25 */
26SkXfermode::Mode op_to_mode(SkRegion::Op op) {
27
28 static const SkXfermode::Mode modeMap[] = {
29 SkXfermode::kDstOut_Mode, // kDifference_Op
reed@google.com8d3cd7a2013-01-30 21:36:11 +000030 SkXfermode::kModulate_Mode, // kIntersect_Op
robertphillips@google.com58b20212012-06-27 20:44:52 +000031 SkXfermode::kSrcOver_Mode, // kUnion_Op
32 SkXfermode::kXor_Mode, // kXOR_Op
33 SkXfermode::kClear_Mode, // kReverseDifference_Op
34 SkXfermode::kSrc_Mode, // kReplace_Op
35 };
36
37 return modeMap[op];
38}
39
krajcevski25a67bc2014-07-29 11:44:26 -070040static inline GrPixelConfig fmt_to_config(SkTextureCompressor::Format fmt) {
krajcevski25a67bc2014-07-29 11:44:26 -070041
krajcevski95b1b3d2014-08-07 12:58:38 -070042 GrPixelConfig config;
43 switch (fmt) {
44 case SkTextureCompressor::kLATC_Format:
45 config = kLATC_GrPixelConfig;
46 break;
47
48 case SkTextureCompressor::kR11_EAC_Format:
49 config = kR11_EAC_GrPixelConfig;
50 break;
51
52 case SkTextureCompressor::kASTC_12x12_Format:
53 config = kASTC_12x12_GrPixelConfig;
54 break;
55
56 case SkTextureCompressor::kETC1_Format:
57 config = kETC1_GrPixelConfig;
58 break;
59
60 default:
61 SkDEBUGFAIL("No GrPixelConfig for compression format!");
62 // Best guess
63 config = kAlpha_8_GrPixelConfig;
64 break;
65 }
66
67 return config;
krajcevski25a67bc2014-07-29 11:44:26 -070068}
69
bsalomon4b91f762015-05-19 09:29:46 -070070static bool choose_compressed_fmt(const GrCaps* caps,
krajcevskib3abe902014-07-30 13:08:11 -070071 SkTextureCompressor::Format *fmt) {
halcanary96fcdcc2015-08-27 07:41:13 -070072 if (nullptr == fmt) {
krajcevskib3abe902014-07-30 13:08:11 -070073 return false;
74 }
75
76 // We can't use scratch textures without the ability to update
77 // compressed textures...
78 if (!(caps->compressedTexSubImageSupport())) {
79 return false;
80 }
81
82 // Figure out what our preferred texture type is. If ASTC is available, that always
83 // gives the biggest win. Otherwise, in terms of compression speed and accuracy,
84 // LATC has a slight edge over R11 EAC.
85 if (caps->isConfigTexturable(kASTC_12x12_GrPixelConfig)) {
86 *fmt = SkTextureCompressor::kASTC_12x12_Format;
87 return true;
88 } else if (caps->isConfigTexturable(kLATC_GrPixelConfig)) {
89 *fmt = SkTextureCompressor::kLATC_Format;
90 return true;
91 } else if (caps->isConfigTexturable(kR11_EAC_GrPixelConfig)) {
92 *fmt = SkTextureCompressor::kR11_EAC_Format;
93 return true;
94 }
95
96 return false;
97}
krajcevskib3abe902014-07-30 13:08:11 -070098
robertphillips@google.com58b20212012-06-27 20:44:52 +000099}
100
101/**
102 * Draw a single rect element of the clip stack into the accumulation bitmap
103 */
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000104void GrSWMaskHelper::draw(const SkRect& rect, SkRegion::Op op,
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000105 bool antiAlias, uint8_t alpha) {
robertphillips@google.com58b20212012-06-27 20:44:52 +0000106 SkPaint paint;
107
krajcevski71614ac2014-08-13 10:36:18 -0700108 SkASSERT(kNone_CompressionMode == fCompressionMode);
109
reedcfb6bdf2016-03-29 11:32:50 -0700110 paint.setXfermode(SkXfermode::Make(op_to_mode(op)));
robertphillips@google.com58b20212012-06-27 20:44:52 +0000111 paint.setAntiAlias(antiAlias);
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000112 paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
robertphillips@google.com58b20212012-06-27 20:44:52 +0000113
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000114 fDraw.drawRect(rect, paint);
robertphillips@google.com58b20212012-06-27 20:44:52 +0000115}
116
117/**
118 * Draw a single path element of the clip stack into the accumulation bitmap
119 */
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000120void GrSWMaskHelper::draw(const SkPath& path, const SkStrokeRec& stroke, SkRegion::Op op,
sugoi@google.com12b4e272012-12-06 20:13:11 +0000121 bool antiAlias, uint8_t alpha) {
robertphillips@google.com58b20212012-06-27 20:44:52 +0000122
123 SkPaint paint;
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000124 if (stroke.isHairlineStyle()) {
robertphillips@google.com58b20212012-06-27 20:44:52 +0000125 paint.setStyle(SkPaint::kStroke_Style);
robertphillips@google.com58b20212012-06-27 20:44:52 +0000126 } else {
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000127 if (stroke.isFillStyle()) {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000128 paint.setStyle(SkPaint::kFill_Style);
129 } else {
130 paint.setStyle(SkPaint::kStroke_Style);
131 paint.setStrokeJoin(stroke.getJoin());
132 paint.setStrokeCap(stroke.getCap());
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000133 paint.setStrokeWidth(stroke.getWidth());
robertphillips@google.com58b20212012-06-27 20:44:52 +0000134 }
135 }
reed@google.com84e922b2013-11-04 20:57:36 +0000136 paint.setAntiAlias(antiAlias);
reed@google.com84e922b2013-11-04 20:57:36 +0000137
krajcevskib8ccc2f2014-08-07 08:15:14 -0700138 SkTBlitterAllocator allocator;
halcanary96fcdcc2015-08-27 07:41:13 -0700139 SkBlitter* blitter = nullptr;
krajcevskib8ccc2f2014-08-07 08:15:14 -0700140 if (kBlitter_CompressionMode == fCompressionMode) {
bsalomon49f085d2014-09-05 13:34:00 -0700141 SkASSERT(fCompressedBuffer.get());
krajcevskib8ccc2f2014-08-07 08:15:14 -0700142 blitter = SkTextureCompressor::CreateBlitterForFormat(
reed41e010c2015-06-09 12:16:53 -0700143 fPixels.width(), fPixels.height(), fCompressedBuffer.get(), &allocator,
144 fCompressedFormat);
krajcevskib8ccc2f2014-08-07 08:15:14 -0700145 }
146
reed@google.com126f7f52013-11-07 16:06:53 +0000147 if (SkRegion::kReplace_Op == op && 0xFF == alpha) {
148 SkASSERT(0xFF == paint.getAlpha());
krajcevskib8ccc2f2014-08-07 08:15:14 -0700149 fDraw.drawPathCoverage(path, paint, blitter);
reed@google.com126f7f52013-11-07 16:06:53 +0000150 } else {
151 paint.setXfermodeMode(op_to_mode(op));
152 paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
krajcevskib8ccc2f2014-08-07 08:15:14 -0700153 fDraw.drawPath(path, paint, blitter);
reed@google.com126f7f52013-11-07 16:06:53 +0000154 }
robertphillips@google.com58b20212012-06-27 20:44:52 +0000155}
156
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000157bool GrSWMaskHelper::init(const SkIRect& resultBounds,
krajcevski71614ac2014-08-13 10:36:18 -0700158 const SkMatrix* matrix,
159 bool allowCompression) {
bsalomon49f085d2014-09-05 13:34:00 -0700160 if (matrix) {
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000161 fMatrix = *matrix;
robertphillips@google.com58b20212012-06-27 20:44:52 +0000162 } else {
163 fMatrix.setIdentity();
164 }
165
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000166 // Now translate so the bound's UL corner is at the origin
167 fMatrix.postTranslate(-resultBounds.fLeft * SK_Scalar1,
168 -resultBounds.fTop * SK_Scalar1);
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000169 SkIRect bounds = SkIRect::MakeWH(resultBounds.width(),
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000170 resultBounds.height());
krajcevski25a67bc2014-07-29 11:44:26 -0700171
krajcevski71614ac2014-08-13 10:36:18 -0700172 if (allowCompression &&
bsalomon76228632015-05-29 08:02:10 -0700173 fContext->caps()->drawPathMasksToCompressedTexturesSupport() &&
174 choose_compressed_fmt(fContext->caps(), &fCompressedFormat)) {
krajcevskib8ccc2f2014-08-07 08:15:14 -0700175 fCompressionMode = kCompress_CompressionMode;
176 }
krajcevski25a67bc2014-07-29 11:44:26 -0700177
krajcevskib8ccc2f2014-08-07 08:15:14 -0700178 // Make sure that the width is a multiple of the desired block dimensions
179 // to allow for specialized SIMD instructions that compress multiple blocks at a time.
180 int cmpWidth = bounds.fRight;
181 int cmpHeight = bounds.fBottom;
182 if (kCompress_CompressionMode == fCompressionMode) {
krajcevskib3abe902014-07-30 13:08:11 -0700183 int dimX, dimY;
184 SkTextureCompressor::GetBlockDimensions(fCompressedFormat, &dimX, &dimY);
krajcevskib8ccc2f2014-08-07 08:15:14 -0700185 cmpWidth = dimX * ((cmpWidth + (dimX - 1)) / dimX);
186 cmpHeight = dimY * ((cmpHeight + (dimY - 1)) / dimY);
187
188 // Can we create a blitter?
189 if (SkTextureCompressor::ExistsBlitterForFormat(fCompressedFormat)) {
190 int cmpSz = SkTextureCompressor::GetCompressedDataSize(
191 fCompressedFormat, cmpWidth, cmpHeight);
192
193 SkASSERT(cmpSz > 0);
halcanary96fcdcc2015-08-27 07:41:13 -0700194 SkASSERT(nullptr == fCompressedBuffer.get());
krajcevskib8ccc2f2014-08-07 08:15:14 -0700195 fCompressedBuffer.reset(cmpSz);
196 fCompressionMode = kBlitter_CompressionMode;
197 }
halcanary9d524f22016-03-29 09:03:52 -0700198 }
krajcevskib8ccc2f2014-08-07 08:15:14 -0700199
reed41e010c2015-06-09 12:16:53 -0700200 sk_bzero(&fDraw, sizeof(fDraw));
201
krajcevskib8ccc2f2014-08-07 08:15:14 -0700202 // If we don't have a custom blitter, then we either need a bitmap to compress
203 // from or a bitmap that we're going to use as a texture. In any case, we should
204 // allocate the pixels for a bitmap
205 const SkImageInfo bmImageInfo = SkImageInfo::MakeA8(cmpWidth, cmpHeight);
206 if (kBlitter_CompressionMode != fCompressionMode) {
reed41e010c2015-06-09 12:16:53 -0700207 if (!fPixels.tryAlloc(bmImageInfo)) {
krajcevskib8ccc2f2014-08-07 08:15:14 -0700208 return false;
209 }
reed41e010c2015-06-09 12:16:53 -0700210 fPixels.erase(0);
krajcevskib3abe902014-07-30 13:08:11 -0700211 } else {
krajcevskib8ccc2f2014-08-07 08:15:14 -0700212 // Otherwise, we just need to remember how big the buffer is...
reed41e010c2015-06-09 12:16:53 -0700213 fPixels.reset(bmImageInfo);
krajcevskib3abe902014-07-30 13:08:11 -0700214 }
reed41e010c2015-06-09 12:16:53 -0700215 fDraw.fDst = fPixels;
robertphillips@google.com58b20212012-06-27 20:44:52 +0000216 fRasterClip.setRect(bounds);
reed41e010c2015-06-09 12:16:53 -0700217 fDraw.fRC = &fRasterClip;
reed41e010c2015-06-09 12:16:53 -0700218 fDraw.fMatrix = &fMatrix;
robertphillips@google.com58b20212012-06-27 20:44:52 +0000219 return true;
220}
221
222/**
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000223 * Get a texture (from the texture cache) of the correct size & format.
robertphillips@google.com58b20212012-06-27 20:44:52 +0000224 */
bsalomone3059732014-10-14 11:47:22 -0700225GrTexture* GrSWMaskHelper::createTexture() {
bsalomonf2703d82014-10-28 14:33:06 -0700226 GrSurfaceDesc desc;
reed41e010c2015-06-09 12:16:53 -0700227 desc.fWidth = fPixels.width();
228 desc.fHeight = fPixels.height();
krajcevskib3abe902014-07-30 13:08:11 -0700229 desc.fConfig = kAlpha_8_GrPixelConfig;
krajcevskifb4f5cb2014-06-12 09:20:38 -0700230
krajcevskib8ccc2f2014-08-07 08:15:14 -0700231 if (kNone_CompressionMode != fCompressionMode) {
krajcevskib577c552014-07-16 13:26:43 -0700232
krajcevski25a67bc2014-07-29 11:44:26 -0700233#ifdef SK_DEBUG
krajcevskib3abe902014-07-30 13:08:11 -0700234 int dimX, dimY;
235 SkTextureCompressor::GetBlockDimensions(fCompressedFormat, &dimX, &dimY);
236 SkASSERT((desc.fWidth % dimX) == 0);
237 SkASSERT((desc.fHeight % dimY) == 0);
krajcevski25a67bc2014-07-29 11:44:26 -0700238#endif
239
krajcevskib3abe902014-07-30 13:08:11 -0700240 desc.fConfig = fmt_to_config(fCompressedFormat);
bsalomon76228632015-05-29 08:02:10 -0700241 SkASSERT(fContext->caps()->isConfigTexturable(desc.fConfig));
krajcevskifb4f5cb2014-06-12 09:20:38 -0700242 }
robertphillips@google.com58b20212012-06-27 20:44:52 +0000243
bsalomoneae62002015-07-31 13:59:30 -0700244 return fContext->textureProvider()->createApproxTexture(desc);
robertphillips@google.com58b20212012-06-27 20:44:52 +0000245}
246
bsalomonf2703d82014-10-28 14:33:06 -0700247void GrSWMaskHelper::sendTextureData(GrTexture *texture, const GrSurfaceDesc& desc,
bsalomonef3fcd82014-12-12 08:51:38 -0800248 const void *data, size_t rowbytes) {
krajcevskifb4f5cb2014-06-12 09:20:38 -0700249 // Since we're uploading to it, and it's compressed, 'texture' shouldn't
250 // have a render target.
halcanary96fcdcc2015-08-27 07:41:13 -0700251 SkASSERT(nullptr == texture->asRenderTarget());
krajcevskifb4f5cb2014-06-12 09:20:38 -0700252
bsalomon00422452016-02-16 11:36:56 -0800253 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig, data, rowbytes);
krajcevski5c2fca02014-06-10 17:25:28 -0700254}
255
bsalomonf2703d82014-10-28 14:33:06 -0700256void GrSWMaskHelper::compressTextureData(GrTexture *texture, const GrSurfaceDesc& desc) {
krajcevskib577c552014-07-16 13:26:43 -0700257
258 SkASSERT(GrPixelConfigIsCompressed(desc.fConfig));
krajcevskib3abe902014-07-30 13:08:11 -0700259 SkASSERT(fmt_to_config(fCompressedFormat) == desc.fConfig);
krajcevskib577c552014-07-16 13:26:43 -0700260
reed41e010c2015-06-09 12:16:53 -0700261 SkAutoDataUnref cmpData(SkTextureCompressor::CompressBitmapToFormat(fPixels,
262 fCompressedFormat));
bsalomon49f085d2014-09-05 13:34:00 -0700263 SkASSERT(cmpData);
krajcevskib577c552014-07-16 13:26:43 -0700264
265 this->sendTextureData(texture, desc, cmpData->data(), 0);
266}
267
robertphillips@google.com58b20212012-06-27 20:44:52 +0000268/**
269 * Move the result of the software mask generation back to the gpu
270 */
robertphillips@google.comd92cf2e2013-07-19 18:13:02 +0000271void GrSWMaskHelper::toTexture(GrTexture *texture) {
bsalomonf2703d82014-10-28 14:33:06 -0700272 GrSurfaceDesc desc;
reed41e010c2015-06-09 12:16:53 -0700273 desc.fWidth = fPixels.width();
274 desc.fHeight = fPixels.height();
krajcevskifb4f5cb2014-06-12 09:20:38 -0700275 desc.fConfig = texture->config();
cblumeed828002016-02-16 13:00:01 -0800276
krajcevskifb4f5cb2014-06-12 09:20:38 -0700277 // First see if we should compress this texture before uploading.
krajcevskib8ccc2f2014-08-07 08:15:14 -0700278 switch (fCompressionMode) {
279 case kNone_CompressionMode:
reed41e010c2015-06-09 12:16:53 -0700280 this->sendTextureData(texture, desc, fPixels.addr(), fPixels.rowBytes());
krajcevskib8ccc2f2014-08-07 08:15:14 -0700281 break;
282
283 case kCompress_CompressionMode:
284 this->compressTextureData(texture, desc);
285 break;
286
287 case kBlitter_CompressionMode:
bsalomon49f085d2014-09-05 13:34:00 -0700288 SkASSERT(fCompressedBuffer.get());
krajcevskib8ccc2f2014-08-07 08:15:14 -0700289 this->sendTextureData(texture, desc, fCompressedBuffer.get(), 0);
290 break;
krajcevskifb4f5cb2014-06-12 09:20:38 -0700291 }
robertphillips@google.com58b20212012-06-27 20:44:52 +0000292}
293
jvanverthfa38a302014-10-06 05:59:05 -0700294/**
295 * Convert mask generation results to a signed distance field
296 */
297void GrSWMaskHelper::toSDF(unsigned char* sdf) {
reed41e010c2015-06-09 12:16:53 -0700298 SkGenerateDistanceFieldFromA8Image(sdf, (const unsigned char*)fPixels.addr(),
299 fPixels.width(), fPixels.height(), fPixels.rowBytes());
jvanverthfa38a302014-10-06 05:59:05 -0700300}
301
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000302////////////////////////////////////////////////////////////////////////////////
303/**
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000304 * Software rasterizes path to A8 mask (possibly using the context's matrix)
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000305 * and uploads the result to a scratch texture. Returns the resulting
halcanary96fcdcc2015-08-27 07:41:13 -0700306 * texture on success; nullptr on failure.
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000307 */
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000308GrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context,
309 const SkPath& path,
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000310 const SkStrokeRec& stroke,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000311 const SkIRect& resultBounds,
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000312 bool antiAlias,
joshualitt8059eb92014-12-29 15:10:07 -0800313 const SkMatrix* matrix) {
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000314 GrSWMaskHelper helper(context);
315
reed@google.com84e922b2013-11-04 20:57:36 +0000316 if (!helper.init(resultBounds, matrix)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700317 return nullptr;
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000318 }
319
sugoi@google.com12b4e272012-12-06 20:13:11 +0000320 helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF);
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000321
bsalomone3059732014-10-14 11:47:22 -0700322 GrTexture* texture(helper.createTexture());
323 if (!texture) {
halcanary96fcdcc2015-08-27 07:41:13 -0700324 return nullptr;
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000325 }
326
bsalomone3059732014-10-14 11:47:22 -0700327 helper.toTexture(texture);
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000328
bsalomone3059732014-10-14 11:47:22 -0700329 return texture;
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000330}
331
332void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture,
333 GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800334 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800335 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800336 const SkMatrix& viewMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000337 const SkIRect& rect) {
joshualittd27f73e2014-12-29 07:43:36 -0800338 SkMatrix invert;
joshualitt8059eb92014-12-29 15:10:07 -0800339 if (!viewMatrix.invert(&invert)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000340 return;
341 }
joshualitt4421a4c2015-07-13 09:36:41 -0700342 GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps(*pipelineBuilder);
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000343
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000344 SkRect dstRect = SkRect::MakeLTRB(SK_Scalar1 * rect.fLeft,
345 SK_Scalar1 * rect.fTop,
346 SK_Scalar1 * rect.fRight,
347 SK_Scalar1 * rect.fBottom);
bsalomon@google.comc7818882013-03-20 19:19:53 +0000348
bsalomon309d4d52014-12-18 10:17:44 -0800349 // We use device coords to compute the texture coordinates. We take the device coords and apply
350 // a translation so that the top-left of the device bounds maps to 0,0, and then a scaling
351 // matrix to normalized coords.
bsalomon@google.comc7818882013-03-20 19:19:53 +0000352 SkMatrix maskMatrix;
353 maskMatrix.setIDiv(texture->width(), texture->height());
354 maskMatrix.preTranslate(SkIntToScalar(-rect.fLeft), SkIntToScalar(-rect.fTop));
bsalomon@google.comc7818882013-03-20 19:19:53 +0000355
bsalomonac856c92015-08-27 06:30:17 -0700356 pipelineBuilder->addCoverageFragmentProcessor(
bsalomon4a339522015-10-06 08:40:50 -0700357 GrSimpleTextureEffect::Create(texture,
bsalomon@google.comc7818882013-03-20 19:19:53 +0000358 maskMatrix,
humper@google.comb86add12013-07-25 18:49:07 +0000359 GrTextureParams::kNone_FilterMode,
bsalomon309d4d52014-12-18 10:17:44 -0800360 kDevice_GrCoordSet))->unref();
bsalomon@google.comc7818882013-03-20 19:19:53 +0000361
joshualitt04194f32016-01-13 10:08:27 -0800362 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateNonAAFill(color, SkMatrix::I(),
363 dstRect, nullptr, &invert));
364 target->drawBatch(*pipelineBuilder, batch);
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000365}