1 /*
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"
9
10 #include "GrProxyProvider.h"
11 #include "GrRecordingContext.h"
12 #include "GrRecordingContextPriv.h"
13 #include "GrShape.h"
14 #include "GrSurfaceContext.h"
15 #include "GrTextureProxy.h"
16
17 /*
18 * Convert a boolean operation into a transfer mode code
19 */
op_to_mode(SkRegion::Op op)20 static SkBlendMode op_to_mode(SkRegion::Op op) {
21
22 static const SkBlendMode modeMap[] = {
23 SkBlendMode::kDstOut, // kDifference_Op
24 SkBlendMode::kModulate, // kIntersect_Op
25 SkBlendMode::kSrcOver, // kUnion_Op
26 SkBlendMode::kXor, // kXOR_Op
27 SkBlendMode::kClear, // kReverseDifference_Op
28 SkBlendMode::kSrc, // kReplace_Op
29 };
30
31 return modeMap[op];
32 }
33
34 /**
35 * Draw a single rect element of the clip stack into the accumulation bitmap
36 */
drawRect(const SkRect & rect,const SkMatrix & matrix,SkRegion::Op op,GrAA aa,uint8_t alpha)37 void GrSWMaskHelper::drawRect(const SkRect& rect, const SkMatrix& matrix, SkRegion::Op op, GrAA aa,
38 uint8_t alpha) {
39 SkPaint paint;
40 paint.setBlendMode(op_to_mode(op));
41 paint.setAntiAlias(GrAA::kYes == aa);
42 paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
43
44 SkMatrix translatedMatrix = matrix;
45 translatedMatrix.postTranslate(fTranslate.fX, fTranslate.fY);
46 fDraw.fMatrix = &translatedMatrix;
47
48 fDraw.drawRect(rect, paint);
49 }
50
51 /**
52 * Draw a single path element of the clip stack into the accumulation bitmap
53 */
drawShape(const GrShape & shape,const SkMatrix & matrix,SkRegion::Op op,GrAA aa,uint8_t alpha)54 void GrSWMaskHelper::drawShape(const GrShape& shape, const SkMatrix& matrix, SkRegion::Op op,
55 GrAA aa, uint8_t alpha) {
56 SkPaint paint;
57 paint.setPathEffect(shape.style().refPathEffect());
58 shape.style().strokeRec().applyToPaint(&paint);
59 paint.setAntiAlias(GrAA::kYes == aa);
60
61 SkMatrix translatedMatrix = matrix;
62 translatedMatrix.postTranslate(fTranslate.fX, fTranslate.fY);
63 fDraw.fMatrix = &translatedMatrix;
64
65 SkPath path;
66 shape.asPath(&path);
67 if (SkRegion::kReplace_Op == op && 0xFF == alpha) {
68 SkASSERT(0xFF == paint.getAlpha());
69 fDraw.drawPathCoverage(path, paint);
70 } else {
71 paint.setBlendMode(op_to_mode(op));
72 paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
73 fDraw.drawPath(path, paint);
74 }
75 };
76
init(const SkIRect & resultBounds)77 bool GrSWMaskHelper::init(const SkIRect& resultBounds) {
78 // We will need to translate draws so the bound's UL corner is at the origin
79 fTranslate = {-SkIntToScalar(resultBounds.fLeft), -SkIntToScalar(resultBounds.fTop)};
80 SkIRect bounds = SkIRect::MakeWH(resultBounds.width(), resultBounds.height());
81
82 const SkImageInfo bmImageInfo = SkImageInfo::MakeA8(bounds.width(), bounds.height());
83 if (!fPixels->tryAlloc(bmImageInfo)) {
84 return false;
85 }
86 fPixels->erase(0);
87
88 fDraw.fDst = *fPixels;
89 fRasterClip.setRect(bounds);
90 fDraw.fRC = &fRasterClip;
91 return true;
92 }
93
toTextureProxy(GrRecordingContext * context,SkBackingFit fit)94 sk_sp<GrTextureProxy> GrSWMaskHelper::toTextureProxy(GrRecordingContext* context,
95 SkBackingFit fit) {
96 SkImageInfo ii = SkImageInfo::MakeA8(fPixels->width(), fPixels->height());
97 size_t rowBytes = fPixels->rowBytes();
98
99 sk_sp<SkData> data = fPixels->detachPixelsAsData();
100 if (!data) {
101 return nullptr;
102 }
103
104 sk_sp<SkImage> img = SkImage::MakeRasterData(ii, std::move(data), rowBytes);
105 if (!img) {
106 return nullptr;
107 }
108
109 // TODO: http://skbug.com/8422: Although this fixes http://skbug.com/8351, it seems like these
110 // should just participate in the normal allocation process and not need the pending IO flag.
111 auto surfaceFlags = GrInternalSurfaceFlags::kNone;
112 if (!context->priv().proxyProvider()->renderingDirectly()) {
113 // In DDL mode, this texture proxy will be instantiated at flush time, therfore it cannot
114 // have pending IO.
115 surfaceFlags |= GrInternalSurfaceFlags::kNoPendingIO;
116 }
117 auto clearFlag = kNone_GrSurfaceFlags;
118 // In a WASM build on Firefox, we see warnings like
119 // WebGL warning: texSubImage2D: This operation requires zeroing texture data. This is slow.
120 // WebGL warning: texSubImage2D: Texture has not been initialized prior to a partial upload,
121 // forcing the browser to clear it. This may be slow.
122 // Setting the initial clear seems to make those warnings go away and offers a substantial
123 // boost in performance in Firefox. Chrome sees a more modest increase.
124 #if IS_WEBGL==1
125 clearFlag = kPerformInitialClear_GrSurfaceFlag;
126 #endif
127 return context->priv().proxyProvider()->createTextureProxy(
128 std::move(img), clearFlag, 1, SkBudgeted::kYes, fit, surfaceFlags);
129 }
130