• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 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 "gm.h"
9 
10 #include "SkArenaAlloc.h"
11 #include "SkBlitter.h"
12 #include "SkCanvas.h"
13 #include "SkColor.h"
14 #include "SkImage.h"
15 #include "SkImageInfo.h"
16 #include "SkLinearBitmapPipeline.h"
17 #include "SkXfermodePriv.h"
18 #include "SkPM4fPriv.h"
19 #include "SkShader.h"
20 
fill_in_bits(SkBitmap & bm,SkIRect ir,SkColor c,bool premul)21 static void fill_in_bits(SkBitmap& bm, SkIRect ir, SkColor c, bool premul) {
22     bm.allocN32Pixels(ir.width(), ir.height());
23     SkPixmap pm;
24     bm.peekPixels(&pm);
25 
26     SkPMColor b = SkColorSetARGBMacro(255, 0, 0, 0);
27     SkPMColor w;
28     if (premul) {
29         w = SkPreMultiplyColor(c);
30     } else {
31         w = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), SkColorGetG(c), SkColorGetB(c));
32     }
33 
34     for (int y = 0; y < ir.height(); y++) {
35         for (int x = 0; x < ir.width(); x++) {
36             if ((x ^ y)  & 16) {
37                 *pm.writable_addr32(x, y) = b;
38             } else {
39                 *pm.writable_addr32(x, y) = w;
40             }
41         }
42     }
43 }
44 
draw_rect_orig(SkCanvas * canvas,const SkRect & r,SkColor c,const SkMatrix * mat,bool useBilerp)45 static void draw_rect_orig(SkCanvas* canvas, const SkRect& r, SkColor c, const SkMatrix* mat, bool useBilerp) {
46     const SkIRect ir = r.round();
47 
48     SkBitmap bmsrc;
49     fill_in_bits(bmsrc, ir, c, true);
50 
51     SkPixmap pmsrc;
52     bmsrc.peekPixels(&pmsrc);
53 
54     SkBitmap bmdst;
55     bmdst.allocN32Pixels(ir.width(), ir.height());
56     bmdst.eraseColor(0xFFFFFFFF);
57     SkPixmap pmdst;
58     bmdst.peekPixels(&pmdst);
59 
60     SkImageInfo info = SkImageInfo::MakeN32Premul(ir.width(), ir.height());
61 
62     sk_sp<SkImage> image(SkImage::MakeRasterCopy(SkPixmap(info, pmsrc.addr32(), pmsrc.rowBytes())));
63     SkPaint paint;
64     SkArenaAlloc alloc{0};
65 
66     sk_sp<SkShader> shader = image->makeShader(SkShader::kRepeat_TileMode,
67                                                SkShader::kRepeat_TileMode);
68 
69     if (useBilerp) {
70         paint.setFilterQuality(SkFilterQuality::kLow_SkFilterQuality);
71     } else {
72         paint.setFilterQuality(SkFilterQuality::kNone_SkFilterQuality);
73     }
74     paint.setShader(std::move(shader));
75     const SkShader::ContextRec rec(paint, *mat, nullptr,
76                                    SkBlitter::PreferredShaderDest(pmsrc.info()),
77                                    canvas->imageInfo().colorSpace());
78 
79     SkShader::Context* ctx = paint.getShader()->makeContext(rec, &alloc);
80 
81     for (int y = 0; y < ir.height(); y++) {
82         ctx->shadeSpan(0, y, pmdst.writable_addr32(0, y), ir.width());
83     }
84 
85     canvas->drawBitmap(bmdst, r.left(), r.top(), nullptr);
86 }
87 
draw_rect_fp(SkCanvas * canvas,const SkRect & r,SkColor c,const SkMatrix * mat,bool useBilerp)88 static void draw_rect_fp(SkCanvas* canvas, const SkRect& r, SkColor c, const SkMatrix* mat, bool useBilerp) {
89     const SkIRect ir = r.round();
90 
91     SkBitmap bmsrc;
92     fill_in_bits(bmsrc, ir, c, true);
93     SkPixmap pmsrc;
94     bmsrc.peekPixels(&pmsrc);
95 
96     SkBitmap bmdst;
97     bmdst.allocN32Pixels(ir.width(), ir.height());
98     bmdst.eraseColor(0xFFFFFFFF);
99     SkPixmap pmdst;
100     bmdst.peekPixels(&pmdst);
101 
102     SkPM4f* dstBits = new SkPM4f[ir.width()];
103 
104     SkMatrix inv;
105     bool trash = mat->invert(&inv);
106     sk_ignore_unused_variable(trash);
107 
108     SkFilterQuality filterQuality;
109     if (useBilerp) {
110         filterQuality = SkFilterQuality::kLow_SkFilterQuality;
111     } else {
112         filterQuality = SkFilterQuality::kNone_SkFilterQuality;
113     }
114 
115     uint32_t flags = 0;
116     auto procN = SkXfermode::GetD32Proc(SkBlendMode::kSrcOver, flags);
117 
118     char storage[512];
119     SkArenaAlloc allocator{storage, sizeof(storage)};
120     SkLinearBitmapPipeline pipeline{
121             inv, filterQuality,
122             SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode,
123             SK_ColorBLACK, pmsrc, &allocator};
124 
125     for (int y = 0; y < ir.height(); y++) {
126         pipeline.shadeSpan4f(0, y, dstBits, ir.width());
127         procN(SkBlendMode::kSrcOver, pmdst.writable_addr32(0, y), dstBits, ir.width(), nullptr);
128     }
129 
130     delete [] dstBits;
131 
132     canvas->drawBitmap(bmdst, r.left(), r.top(), nullptr);
133 }
134 
draw_rect_none(SkCanvas * canvas,const SkRect & r,SkColor c)135 static void draw_rect_none(SkCanvas* canvas, const SkRect& r, SkColor c) {
136     const SkIRect ir = r.round();
137 
138     SkBitmap bm;
139     fill_in_bits(bm, ir, c, true);
140 
141     canvas->drawBitmap(bm, r.left(), r.top(), nullptr);
142 }
143 
144 /*
145  *  Test SkXfer4fProcs directly for src-over, comparing them to current SkColor blits.
146  */
147 DEF_SIMPLE_GM(linear_pipeline, canvas, 580, 2200) {
148     const int IW = 50;
149     const SkScalar W = IW;
150     const SkScalar H = 100;
151 
152     const SkColor colors[] = {
153         0x880000FF, 0x8800FF00, 0x88FF0000, 0x88000000,
154         SK_ColorBLUE, SK_ColorGREEN, SK_ColorRED, SK_ColorBLACK,
155     };
156 
157     canvas->translate(20, 20);
158 
159     SkMatrix mi = SkMatrix::I();
160     SkMatrix mlr;
161     mlr.setScale(-1.0f, 1.0f, 20, 0.0f);
162     SkMatrix mt;
163     mt.setTranslate(8, 8);
164     SkMatrix mt2;
165     mt2.setTranslate(-18, -18);
166     SkMatrix ms;
167     ms.setScale(2.7f, 2.7f, -1.5f, 0);
168     SkMatrix ms2;
169     ms2.setScale(-0.4f, 0.4f);
170     SkMatrix mr;
171     mr.setRotate(10);
172 
173     const SkMatrix* mats[] = {nullptr, &mi, &mlr, &mt, &mt2, &ms, &ms2, &mr};
174 
175     const SkRect r = SkRect::MakeWH(W, H);
176     bool useBilerp = false;
177     while (true) {
178         canvas->save();
179         for (auto mat : mats) {
180             canvas->save();
181             for (SkColor c : colors) {
182                 if (mat == nullptr) {
183                     SkPaint p;
184                     p.setColor(c);
185                     draw_rect_none(canvas, r, c);
186                     canvas->translate(W + 20, 0);
187                     draw_rect_none(canvas, r, c);
188 
189                 } else {
190                     draw_rect_orig(canvas, r, c, mat, useBilerp);
191                     canvas->translate(W + 20, 0);
192                     draw_rect_fp(canvas, r, c, mat, useBilerp);
193                 }
194                 canvas->translate(W + 20, 0);
195             }
196             canvas->restore();
197             canvas->translate(0, H + 20);
198         }
199         canvas->restore();
200         canvas->translate(0, (H + 20) * SK_ARRAY_COUNT(mats));
201         if (useBilerp) break;
202         useBilerp = true;
203     }
204 }
205