| herb | feec878 | 2016-02-17 10:00:07 -0800 | [diff] [blame] | 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" | 
| fmalita | d0c4e09 | 2016-02-22 17:19:04 -0800 | [diff] [blame^] | 9 | #include "SkBlitter.h" | 
| herb | feec878 | 2016-02-17 10:00:07 -0800 | [diff] [blame] | 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 |  | 
|  | 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 |  | 
|  | 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(); | 
| fmalita | d0c4e09 | 2016-02-22 17:19:04 -0800 | [diff] [blame^] | 71 | const SkShader::ContextRec rec(paint, *mat, nullptr, | 
|  | 72 | SkBlitter::PreferredShaderDest(pmsrc.info())); | 
| fmalita | 8d9f2e4 | 2016-02-22 10:39:41 -0800 | [diff] [blame] | 73 | SkASSERT(paint.getShader()->contextSize(rec) <= sizeof(storage)); | 
| herb | feec878 | 2016-02-17 10:00:07 -0800 | [diff] [blame] | 74 |  | 
| fmalita | 8d9f2e4 | 2016-02-22 10:39:41 -0800 | [diff] [blame] | 75 | SkShader::Context* ctx = paint.getShader()->createContext(rec, storage); | 
| herb | feec878 | 2016-02-17 10:00:07 -0800 | [diff] [blame] | 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 |  | 
|  | 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()]; | 
| herb | feec878 | 2016-02-17 10:00:07 -0800 | [diff] [blame] | 102 |  | 
|  | 103 | SkMatrix inv; | 
|  | 104 | bool trash = mat->invert(&inv); | 
|  | 105 | sk_ignore_unused_variable(trash); | 
|  | 106 |  | 
| herb | c5eddd7 | 2016-02-17 19:50:05 -0800 | [diff] [blame] | 107 | SkFilterQuality filterQuality; | 
|  | 108 | if (useBilerp) { | 
|  | 109 | filterQuality = SkFilterQuality::kLow_SkFilterQuality; | 
|  | 110 | } else { | 
|  | 111 | filterQuality = SkFilterQuality::kNone_SkFilterQuality; | 
|  | 112 | } | 
| herb | feec878 | 2016-02-17 10:00:07 -0800 | [diff] [blame] | 113 |  | 
|  | 114 | uint32_t flags = 0; | 
|  | 115 | //if (kSRGB_SkColorProfileType == profile) { | 
|  | 116 | //flags |= SkXfermode::kDstIsSRGB_PM4fFlag; | 
|  | 117 | //} | 
|  | 118 | const SkXfermode::PM4fState state { nullptr, flags }; | 
|  | 119 | auto procN = SkXfermode::GetPM4fProcN(SkXfermode::kSrcOver_Mode, flags); | 
|  | 120 |  | 
|  | 121 | SkLinearBitmapPipeline pipeline{ | 
| herb | c5eddd7 | 2016-02-17 19:50:05 -0800 | [diff] [blame] | 122 | inv, filterQuality, | 
| herb | ed54504 | 2016-02-18 13:55:02 -0800 | [diff] [blame] | 123 | SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, pmsrc}; | 
| herb | feec878 | 2016-02-17 10:00:07 -0800 | [diff] [blame] | 124 |  | 
|  | 125 | for (int y = 0; y < ir.height(); y++) { | 
|  | 126 | pipeline.shadeSpan4f(0, y, dstBits, ir.width()); | 
|  | 127 | procN(state, 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 |  | 
|  | 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, 1400) { | 
|  | 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 mt; | 
|  | 161 | mt.setTranslate(8, 8); | 
|  | 162 | SkMatrix ms; | 
|  | 163 | ms.setScale(2.7f, 2.7f); | 
|  | 164 | SkMatrix mr; | 
|  | 165 | mr.setRotate(10); | 
|  | 166 |  | 
|  | 167 | const SkMatrix* mats[] = {nullptr, &mi, &mt, &ms, &mr}; | 
|  | 168 |  | 
|  | 169 | const SkRect r = SkRect::MakeWH(W, H); | 
|  | 170 | bool useBilerp = false; | 
|  | 171 | while (true) { | 
|  | 172 | canvas->save(); | 
|  | 173 | for (auto mat : mats) { | 
|  | 174 | canvas->save(); | 
|  | 175 | for (SkColor c : colors) { | 
|  | 176 | if (mat == nullptr) { | 
|  | 177 | SkPaint p; | 
|  | 178 | p.setColor(c); | 
|  | 179 | draw_rect_none(canvas, r, c); | 
|  | 180 | canvas->translate(W + 20, 0); | 
|  | 181 | draw_rect_none(canvas, r, c); | 
|  | 182 |  | 
|  | 183 | } else { | 
|  | 184 | draw_rect_orig(canvas, r, c, mat, useBilerp); | 
|  | 185 | canvas->translate(W + 20, 0); | 
|  | 186 | draw_rect_fp(canvas, r, c, mat, useBilerp); | 
|  | 187 | } | 
|  | 188 | canvas->translate(W + 20, 0); | 
|  | 189 | } | 
|  | 190 | canvas->restore(); | 
|  | 191 | canvas->translate(0, H + 20); | 
|  | 192 | } | 
|  | 193 | canvas->restore(); | 
|  | 194 | canvas->translate(0, (H + 20) * SK_ARRAY_COUNT(mats)); | 
|  | 195 | if (useBilerp) break; | 
|  | 196 | useBilerp = true; | 
|  | 197 | } | 
|  | 198 | } |