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