1feec878e850850cb0a092a765e3af0f5a3fa2a42herb/*
2feec878e850850cb0a092a765e3af0f5a3fa2a42herb * Copyright 2016 Google Inc.
3feec878e850850cb0a092a765e3af0f5a3fa2a42herb *
4feec878e850850cb0a092a765e3af0f5a3fa2a42herb * Use of this source code is governed by a BSD-style license that can be
5feec878e850850cb0a092a765e3af0f5a3fa2a42herb * found in the LICENSE file.
6feec878e850850cb0a092a765e3af0f5a3fa2a42herb */
7feec878e850850cb0a092a765e3af0f5a3fa2a42herb
8feec878e850850cb0a092a765e3af0f5a3fa2a42herb#include "gm.h"
983e939bcb79790f5ae3b28c398fbcf034675a6e5Herb Derby
1083e939bcb79790f5ae3b28c398fbcf034675a6e5Herb Derby#include "SkArenaAlloc.h"
11d0c4e092d54d281991ecfdc2e4ddd5217e45b42afmalita#include "SkBlitter.h"
12feec878e850850cb0a092a765e3af0f5a3fa2a42herb#include "SkCanvas.h"
13feec878e850850cb0a092a765e3af0f5a3fa2a42herb#include "SkColor.h"
14feec878e850850cb0a092a765e3af0f5a3fa2a42herb#include "SkImage.h"
15feec878e850850cb0a092a765e3af0f5a3fa2a42herb#include "SkImageInfo.h"
16feec878e850850cb0a092a765e3af0f5a3fa2a42herb#include "SkLinearBitmapPipeline.h"
17d47067392848ba132d4e86ffbeebe2dcacda9534Mike Reed#include "SkXfermodePriv.h"
18feec878e850850cb0a092a765e3af0f5a3fa2a42herb#include "SkPM4fPriv.h"
19feec878e850850cb0a092a765e3af0f5a3fa2a42herb#include "SkShader.h"
20feec878e850850cb0a092a765e3af0f5a3fa2a42herb
21feec878e850850cb0a092a765e3af0f5a3fa2a42herbstatic void fill_in_bits(SkBitmap& bm, SkIRect ir, SkColor c, bool premul) {
22feec878e850850cb0a092a765e3af0f5a3fa2a42herb    bm.allocN32Pixels(ir.width(), ir.height());
23feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkPixmap pm;
24feec878e850850cb0a092a765e3af0f5a3fa2a42herb    bm.peekPixels(&pm);
25feec878e850850cb0a092a765e3af0f5a3fa2a42herb
26feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkPMColor b = SkColorSetARGBMacro(255, 0, 0, 0);
27feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkPMColor w;
28feec878e850850cb0a092a765e3af0f5a3fa2a42herb    if (premul) {
29feec878e850850cb0a092a765e3af0f5a3fa2a42herb        w = SkPreMultiplyColor(c);
30feec878e850850cb0a092a765e3af0f5a3fa2a42herb    } else {
31feec878e850850cb0a092a765e3af0f5a3fa2a42herb        w = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), SkColorGetG(c), SkColorGetB(c));
32feec878e850850cb0a092a765e3af0f5a3fa2a42herb    }
33feec878e850850cb0a092a765e3af0f5a3fa2a42herb
34feec878e850850cb0a092a765e3af0f5a3fa2a42herb    for (int y = 0; y < ir.height(); y++) {
35feec878e850850cb0a092a765e3af0f5a3fa2a42herb        for (int x = 0; x < ir.width(); x++) {
36feec878e850850cb0a092a765e3af0f5a3fa2a42herb            if ((x ^ y)  & 16) {
37feec878e850850cb0a092a765e3af0f5a3fa2a42herb                *pm.writable_addr32(x, y) = b;
38feec878e850850cb0a092a765e3af0f5a3fa2a42herb            } else {
39feec878e850850cb0a092a765e3af0f5a3fa2a42herb                *pm.writable_addr32(x, y) = w;
40feec878e850850cb0a092a765e3af0f5a3fa2a42herb            }
41feec878e850850cb0a092a765e3af0f5a3fa2a42herb        }
42feec878e850850cb0a092a765e3af0f5a3fa2a42herb    }
43feec878e850850cb0a092a765e3af0f5a3fa2a42herb}
44feec878e850850cb0a092a765e3af0f5a3fa2a42herb
45feec878e850850cb0a092a765e3af0f5a3fa2a42herbstatic void draw_rect_orig(SkCanvas* canvas, const SkRect& r, SkColor c, const SkMatrix* mat, bool useBilerp) {
46feec878e850850cb0a092a765e3af0f5a3fa2a42herb    const SkIRect ir = r.round();
47feec878e850850cb0a092a765e3af0f5a3fa2a42herb
48feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkBitmap bmsrc;
49feec878e850850cb0a092a765e3af0f5a3fa2a42herb    fill_in_bits(bmsrc, ir, c, true);
50feec878e850850cb0a092a765e3af0f5a3fa2a42herb
51feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkPixmap pmsrc;
52feec878e850850cb0a092a765e3af0f5a3fa2a42herb    bmsrc.peekPixels(&pmsrc);
53feec878e850850cb0a092a765e3af0f5a3fa2a42herb
54feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkBitmap bmdst;
55feec878e850850cb0a092a765e3af0f5a3fa2a42herb    bmdst.allocN32Pixels(ir.width(), ir.height());
56feec878e850850cb0a092a765e3af0f5a3fa2a42herb    bmdst.eraseColor(0xFFFFFFFF);
57feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkPixmap pmdst;
58feec878e850850cb0a092a765e3af0f5a3fa2a42herb    bmdst.peekPixels(&pmdst);
59feec878e850850cb0a092a765e3af0f5a3fa2a42herb
6052ede1d905728cdcaa98db1e4a33724f5a85c62dbrianosman    SkImageInfo info = SkImageInfo::MakeN32Premul(ir.width(), ir.height());
61feec878e850850cb0a092a765e3af0f5a3fa2a42herb
629ce9d6772df650ceb0511f275e1a83dffa78ff72reed    sk_sp<SkImage> image(SkImage::MakeRasterCopy(SkPixmap(info, pmsrc.addr32(), pmsrc.rowBytes())));
63feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkPaint paint;
649852dc027f77c20640796d6988b0efcd42aa0b73Herb Derby    SkArenaAlloc alloc{0};
656eff52afb458bf6702a715d88611fd571544ef73herb
666eff52afb458bf6702a715d88611fd571544ef73herb    sk_sp<SkShader> shader = image->makeShader(SkShader::kRepeat_TileMode,
676eff52afb458bf6702a715d88611fd571544ef73herb                                               SkShader::kRepeat_TileMode);
686eff52afb458bf6702a715d88611fd571544ef73herb
69feec878e850850cb0a092a765e3af0f5a3fa2a42herb    if (useBilerp) {
70feec878e850850cb0a092a765e3af0f5a3fa2a42herb        paint.setFilterQuality(SkFilterQuality::kLow_SkFilterQuality);
71feec878e850850cb0a092a765e3af0f5a3fa2a42herb    } else {
72feec878e850850cb0a092a765e3af0f5a3fa2a42herb        paint.setFilterQuality(SkFilterQuality::kNone_SkFilterQuality);
73feec878e850850cb0a092a765e3af0f5a3fa2a42herb    }
746eff52afb458bf6702a715d88611fd571544ef73herb    paint.setShader(std::move(shader));
75d0c4e092d54d281991ecfdc2e4ddd5217e45b42afmalita    const SkShader::ContextRec rec(paint, *mat, nullptr,
7611970e56c10b49ad06adbe9e835d32c00a63dd7dBrian Osman                                   SkBlitter::PreferredShaderDest(pmsrc.info()),
7711970e56c10b49ad06adbe9e835d32c00a63dd7dBrian Osman                                   canvas->imageInfo().colorSpace());
78feec878e850850cb0a092a765e3af0f5a3fa2a42herb
7983e939bcb79790f5ae3b28c398fbcf034675a6e5Herb Derby    SkShader::Context* ctx = paint.getShader()->makeContext(rec, &alloc);
80feec878e850850cb0a092a765e3af0f5a3fa2a42herb
81feec878e850850cb0a092a765e3af0f5a3fa2a42herb    for (int y = 0; y < ir.height(); y++) {
82feec878e850850cb0a092a765e3af0f5a3fa2a42herb        ctx->shadeSpan(0, y, pmdst.writable_addr32(0, y), ir.width());
83feec878e850850cb0a092a765e3af0f5a3fa2a42herb    }
84feec878e850850cb0a092a765e3af0f5a3fa2a42herb
85feec878e850850cb0a092a765e3af0f5a3fa2a42herb    canvas->drawBitmap(bmdst, r.left(), r.top(), nullptr);
86feec878e850850cb0a092a765e3af0f5a3fa2a42herb}
87feec878e850850cb0a092a765e3af0f5a3fa2a42herb
88feec878e850850cb0a092a765e3af0f5a3fa2a42herbstatic void draw_rect_fp(SkCanvas* canvas, const SkRect& r, SkColor c, const SkMatrix* mat, bool useBilerp) {
89feec878e850850cb0a092a765e3af0f5a3fa2a42herb    const SkIRect ir = r.round();
90feec878e850850cb0a092a765e3af0f5a3fa2a42herb
91feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkBitmap bmsrc;
92feec878e850850cb0a092a765e3af0f5a3fa2a42herb    fill_in_bits(bmsrc, ir, c, true);
93feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkPixmap pmsrc;
94feec878e850850cb0a092a765e3af0f5a3fa2a42herb    bmsrc.peekPixels(&pmsrc);
95feec878e850850cb0a092a765e3af0f5a3fa2a42herb
96feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkBitmap bmdst;
97feec878e850850cb0a092a765e3af0f5a3fa2a42herb    bmdst.allocN32Pixels(ir.width(), ir.height());
98feec878e850850cb0a092a765e3af0f5a3fa2a42herb    bmdst.eraseColor(0xFFFFFFFF);
99feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkPixmap pmdst;
100feec878e850850cb0a092a765e3af0f5a3fa2a42herb    bmdst.peekPixels(&pmdst);
101feec878e850850cb0a092a765e3af0f5a3fa2a42herb
102feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkPM4f* dstBits = new SkPM4f[ir.width()];
103feec878e850850cb0a092a765e3af0f5a3fa2a42herb
104feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkMatrix inv;
105feec878e850850cb0a092a765e3af0f5a3fa2a42herb    bool trash = mat->invert(&inv);
106feec878e850850cb0a092a765e3af0f5a3fa2a42herb    sk_ignore_unused_variable(trash);
107feec878e850850cb0a092a765e3af0f5a3fa2a42herb
108c5eddd7d8d67a6e931973a729c5868c155cb751fherb    SkFilterQuality filterQuality;
109c5eddd7d8d67a6e931973a729c5868c155cb751fherb    if (useBilerp) {
110c5eddd7d8d67a6e931973a729c5868c155cb751fherb        filterQuality = SkFilterQuality::kLow_SkFilterQuality;
111c5eddd7d8d67a6e931973a729c5868c155cb751fherb    } else {
112c5eddd7d8d67a6e931973a729c5868c155cb751fherb        filterQuality = SkFilterQuality::kNone_SkFilterQuality;
113c5eddd7d8d67a6e931973a729c5868c155cb751fherb    }
114feec878e850850cb0a092a765e3af0f5a3fa2a42herb
115feec878e850850cb0a092a765e3af0f5a3fa2a42herb    uint32_t flags = 0;
1166a01554e9e8687c56e6b6707e0c6a02062a1824eMike Reed    auto procN = SkXfermode::GetD32Proc(SkBlendMode::kSrcOver, flags);
117feec878e850850cb0a092a765e3af0f5a3fa2a42herb
118dfa492e580269a9f0c357e23d540721b62183c96Herb Derby    char storage[512];
1190497f088bb41338b1b1400556b9b690decc846faHerb Derby    SkArenaAlloc allocator{storage, sizeof(storage)};
120feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkLinearBitmapPipeline pipeline{
121c5eddd7d8d67a6e931973a729c5868c155cb751fherb            inv, filterQuality,
122dfa492e580269a9f0c357e23d540721b62183c96Herb Derby            SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode,
123dfa492e580269a9f0c357e23d540721b62183c96Herb Derby            SK_ColorBLACK, pmsrc, &allocator};
124feec878e850850cb0a092a765e3af0f5a3fa2a42herb
125feec878e850850cb0a092a765e3af0f5a3fa2a42herb    for (int y = 0; y < ir.height(); y++) {
126feec878e850850cb0a092a765e3af0f5a3fa2a42herb        pipeline.shadeSpan4f(0, y, dstBits, ir.width());
1276a01554e9e8687c56e6b6707e0c6a02062a1824eMike Reed        procN(SkBlendMode::kSrcOver, pmdst.writable_addr32(0, y), dstBits, ir.width(), nullptr);
128feec878e850850cb0a092a765e3af0f5a3fa2a42herb    }
129feec878e850850cb0a092a765e3af0f5a3fa2a42herb
130feec878e850850cb0a092a765e3af0f5a3fa2a42herb    delete [] dstBits;
131feec878e850850cb0a092a765e3af0f5a3fa2a42herb
132feec878e850850cb0a092a765e3af0f5a3fa2a42herb    canvas->drawBitmap(bmdst, r.left(), r.top(), nullptr);
133feec878e850850cb0a092a765e3af0f5a3fa2a42herb}
134feec878e850850cb0a092a765e3af0f5a3fa2a42herb
135feec878e850850cb0a092a765e3af0f5a3fa2a42herbstatic void draw_rect_none(SkCanvas* canvas, const SkRect& r, SkColor c) {
136feec878e850850cb0a092a765e3af0f5a3fa2a42herb    const SkIRect ir = r.round();
137feec878e850850cb0a092a765e3af0f5a3fa2a42herb
138feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkBitmap bm;
139feec878e850850cb0a092a765e3af0f5a3fa2a42herb    fill_in_bits(bm, ir, c, true);
140feec878e850850cb0a092a765e3af0f5a3fa2a42herb
141feec878e850850cb0a092a765e3af0f5a3fa2a42herb    canvas->drawBitmap(bm, r.left(), r.top(), nullptr);
142feec878e850850cb0a092a765e3af0f5a3fa2a42herb}
143feec878e850850cb0a092a765e3af0f5a3fa2a42herb
144feec878e850850cb0a092a765e3af0f5a3fa2a42herb/*
145feec878e850850cb0a092a765e3af0f5a3fa2a42herb *  Test SkXfer4fProcs directly for src-over, comparing them to current SkColor blits.
146feec878e850850cb0a092a765e3af0f5a3fa2a42herb */
1479466571f8ebde1429cca7b6dcd2d4b85bad1b088herbDEF_SIMPLE_GM(linear_pipeline, canvas, 580, 2200) {
148feec878e850850cb0a092a765e3af0f5a3fa2a42herb    const int IW = 50;
149feec878e850850cb0a092a765e3af0f5a3fa2a42herb    const SkScalar W = IW;
150feec878e850850cb0a092a765e3af0f5a3fa2a42herb    const SkScalar H = 100;
151feec878e850850cb0a092a765e3af0f5a3fa2a42herb
152feec878e850850cb0a092a765e3af0f5a3fa2a42herb    const SkColor colors[] = {
153feec878e850850cb0a092a765e3af0f5a3fa2a42herb        0x880000FF, 0x8800FF00, 0x88FF0000, 0x88000000,
154feec878e850850cb0a092a765e3af0f5a3fa2a42herb        SK_ColorBLUE, SK_ColorGREEN, SK_ColorRED, SK_ColorBLACK,
155feec878e850850cb0a092a765e3af0f5a3fa2a42herb    };
156feec878e850850cb0a092a765e3af0f5a3fa2a42herb
157feec878e850850cb0a092a765e3af0f5a3fa2a42herb    canvas->translate(20, 20);
158feec878e850850cb0a092a765e3af0f5a3fa2a42herb
159feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkMatrix mi = SkMatrix::I();
1609466571f8ebde1429cca7b6dcd2d4b85bad1b088herb    SkMatrix mlr;
1619466571f8ebde1429cca7b6dcd2d4b85bad1b088herb    mlr.setScale(-1.0f, 1.0f, 20, 0.0f);
162feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkMatrix mt;
163feec878e850850cb0a092a765e3af0f5a3fa2a42herb    mt.setTranslate(8, 8);
1649466571f8ebde1429cca7b6dcd2d4b85bad1b088herb    SkMatrix mt2;
1659466571f8ebde1429cca7b6dcd2d4b85bad1b088herb    mt2.setTranslate(-18, -18);
166feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkMatrix ms;
1676eff52afb458bf6702a715d88611fd571544ef73herb    ms.setScale(2.7f, 2.7f, -1.5f, 0);
1689466571f8ebde1429cca7b6dcd2d4b85bad1b088herb    SkMatrix ms2;
1696eff52afb458bf6702a715d88611fd571544ef73herb    ms2.setScale(-0.4f, 0.4f);
170feec878e850850cb0a092a765e3af0f5a3fa2a42herb    SkMatrix mr;
171feec878e850850cb0a092a765e3af0f5a3fa2a42herb    mr.setRotate(10);
172feec878e850850cb0a092a765e3af0f5a3fa2a42herb
1739466571f8ebde1429cca7b6dcd2d4b85bad1b088herb    const SkMatrix* mats[] = {nullptr, &mi, &mlr, &mt, &mt2, &ms, &ms2, &mr};
174feec878e850850cb0a092a765e3af0f5a3fa2a42herb
175feec878e850850cb0a092a765e3af0f5a3fa2a42herb    const SkRect r = SkRect::MakeWH(W, H);
176feec878e850850cb0a092a765e3af0f5a3fa2a42herb    bool useBilerp = false;
177feec878e850850cb0a092a765e3af0f5a3fa2a42herb    while (true) {
178feec878e850850cb0a092a765e3af0f5a3fa2a42herb        canvas->save();
179feec878e850850cb0a092a765e3af0f5a3fa2a42herb        for (auto mat : mats) {
180feec878e850850cb0a092a765e3af0f5a3fa2a42herb            canvas->save();
181feec878e850850cb0a092a765e3af0f5a3fa2a42herb            for (SkColor c : colors) {
182feec878e850850cb0a092a765e3af0f5a3fa2a42herb                if (mat == nullptr) {
183feec878e850850cb0a092a765e3af0f5a3fa2a42herb                    SkPaint p;
184feec878e850850cb0a092a765e3af0f5a3fa2a42herb                    p.setColor(c);
185feec878e850850cb0a092a765e3af0f5a3fa2a42herb                    draw_rect_none(canvas, r, c);
186feec878e850850cb0a092a765e3af0f5a3fa2a42herb                    canvas->translate(W + 20, 0);
187feec878e850850cb0a092a765e3af0f5a3fa2a42herb                    draw_rect_none(canvas, r, c);
188feec878e850850cb0a092a765e3af0f5a3fa2a42herb
189feec878e850850cb0a092a765e3af0f5a3fa2a42herb                } else {
190feec878e850850cb0a092a765e3af0f5a3fa2a42herb                    draw_rect_orig(canvas, r, c, mat, useBilerp);
191feec878e850850cb0a092a765e3af0f5a3fa2a42herb                    canvas->translate(W + 20, 0);
192feec878e850850cb0a092a765e3af0f5a3fa2a42herb                    draw_rect_fp(canvas, r, c, mat, useBilerp);
193feec878e850850cb0a092a765e3af0f5a3fa2a42herb                }
194feec878e850850cb0a092a765e3af0f5a3fa2a42herb                canvas->translate(W + 20, 0);
195feec878e850850cb0a092a765e3af0f5a3fa2a42herb            }
196feec878e850850cb0a092a765e3af0f5a3fa2a42herb            canvas->restore();
197feec878e850850cb0a092a765e3af0f5a3fa2a42herb            canvas->translate(0, H + 20);
198feec878e850850cb0a092a765e3af0f5a3fa2a42herb        }
199feec878e850850cb0a092a765e3af0f5a3fa2a42herb        canvas->restore();
200feec878e850850cb0a092a765e3af0f5a3fa2a42herb        canvas->translate(0, (H + 20) * SK_ARRAY_COUNT(mats));
201feec878e850850cb0a092a765e3af0f5a3fa2a42herb        if (useBilerp) break;
202feec878e850850cb0a092a765e3af0f5a3fa2a42herb        useBilerp = true;
203feec878e850850cb0a092a765e3af0f5a3fa2a42herb    }
204feec878e850850cb0a092a765e3af0f5a3fa2a42herb}
205