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 "GrContext.h"
11 #include "GrContextPriv.h"
12 #include "GrProxyProvider.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  */
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  */
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  */
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 
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 
94 sk_sp<GrTextureProxy> GrSWMaskHelper::toTextureProxy(GrContext* context, SkBackingFit fit) {
95     SkImageInfo ii = SkImageInfo::MakeA8(fPixels->width(), fPixels->height());
96     size_t rowBytes = fPixels->rowBytes();
97 
98     sk_sp<SkData> data = fPixels->detachPixelsAsData();
99     if (!data) {
100         return nullptr;
101     }
102 
103     sk_sp<SkImage> img = SkImage::MakeRasterData(ii, std::move(data), rowBytes);
104     if (!img) {
105         return nullptr;
106     }
107 
108     // TODO: http://skbug.com/8422: Although this fixes http://skbug.com/8351, it seems like these
109     // should just participate in the normal allocation process and not need the pending IO flag.
110     auto surfaceFlags = GrInternalSurfaceFlags::kNone;
111     if (!context->contextPriv().resourceProvider()) {
112         // In DDL mode, this texture proxy will be instantiated at flush time, therfore it cannot
113         // have pending IO.
114         surfaceFlags |= GrInternalSurfaceFlags::kNoPendingIO;
115     }
116     auto clearFlag = kNone_GrSurfaceFlags;
117     // In a WASM build on Firefox, we see warnings like
118     // WebGL warning: texSubImage2D: This operation requires zeroing texture data. This is slow.
119     // WebGL warning: texSubImage2D: Texture has not been initialized prior to a partial upload,
120     //                forcing the browser to clear it. This may be slow.
121     // Setting the initial clear seems to make those warnings go away and offers a substantial
122     // boost in performance in Firefox. Chrome sees a more modest increase.
123 #if IS_WEBGL==1
124     clearFlag = kPerformInitialClear_GrSurfaceFlag;
125 #endif
126     return context->contextPriv().proxyProvider()->createTextureProxy(
127             std::move(img), clearFlag, 1, SkBudgeted::kYes, fit, surfaceFlags);
128 }
129