| 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 "include/core/SkColor.h" | 
|---|
| 9 | #include "include/core/SkColorFilter.h" | 
|---|
| 10 | #include "include/core/SkPaint.h" | 
|---|
| 11 | #include "include/core/SkShader.h" | 
|---|
| 12 | #include "include/private/SkTo.h" | 
|---|
| 13 | #include "src/core/SkArenaAlloc.h" | 
|---|
| 14 | #include "src/core/SkBlendModePriv.h" | 
|---|
| 15 | #include "src/core/SkBlitter.h" | 
|---|
| 16 | #include "src/core/SkColorSpacePriv.h" | 
|---|
| 17 | #include "src/core/SkColorSpaceXformSteps.h" | 
|---|
| 18 | #include "src/core/SkOpts.h" | 
|---|
| 19 | #include "src/core/SkRasterPipeline.h" | 
|---|
| 20 | #include "src/core/SkUtils.h" | 
|---|
| 21 | #include "src/shaders/SkShaderBase.h" | 
|---|
| 22 |  | 
|---|
| 23 | class SkRasterPipelineBlitter final : public SkBlitter { | 
|---|
| 24 | public: | 
|---|
| 25 | // This is our common entrypoint for creating the blitter once we've sorted out shaders. | 
|---|
| 26 | static SkBlitter* Create(const SkPixmap&, const SkPaint&, SkArenaAlloc*, | 
|---|
| 27 | const SkRasterPipeline& shaderPipeline, | 
|---|
| 28 | bool is_opaque, bool is_constant, | 
|---|
| 29 | sk_sp<SkShader> clipShader); | 
|---|
| 30 |  | 
|---|
| 31 | SkRasterPipelineBlitter(SkPixmap dst, | 
|---|
| 32 | SkBlendMode blend, | 
|---|
| 33 | SkArenaAlloc* alloc) | 
|---|
| 34 | : fDst(dst) | 
|---|
| 35 | , fBlend(blend) | 
|---|
| 36 | , fAlloc(alloc) | 
|---|
| 37 | , fColorPipeline(alloc) | 
|---|
| 38 | {} | 
|---|
| 39 |  | 
|---|
| 40 | void blitH     (int x, int y, int w)                            override; | 
|---|
| 41 | void blitAntiH (int x, int y, const SkAlpha[], const int16_t[]) override; | 
|---|
| 42 | void blitAntiH2(int x, int y, U8CPU a0, U8CPU a1)               override; | 
|---|
| 43 | void blitAntiV2(int x, int y, U8CPU a0, U8CPU a1)               override; | 
|---|
| 44 | void blitMask  (const SkMask&, const SkIRect& clip)             override; | 
|---|
| 45 | void blitRect  (int x, int y, int width, int height)            override; | 
|---|
| 46 | void blitV     (int x, int y, int height, SkAlpha alpha)        override; | 
|---|
| 47 |  | 
|---|
| 48 | private: | 
|---|
| 49 | void append_load_dst      (SkRasterPipeline*) const; | 
|---|
| 50 | void append_store         (SkRasterPipeline*) const; | 
|---|
| 51 |  | 
|---|
| 52 | // these check internally, and only append if there was a native clipShader | 
|---|
| 53 | void append_clip_scale    (SkRasterPipeline*) const; | 
|---|
| 54 | void append_clip_lerp     (SkRasterPipeline*) const; | 
|---|
| 55 |  | 
|---|
| 56 | SkPixmap               fDst; | 
|---|
| 57 | SkBlendMode            fBlend; | 
|---|
| 58 | SkArenaAlloc*          fAlloc; | 
|---|
| 59 | SkRasterPipeline       fColorPipeline; | 
|---|
| 60 | // set to pipeline storage (for alpha) if we have a clipShader | 
|---|
| 61 | void*                  fClipShaderBuffer = nullptr; // "native" : float or U16 | 
|---|
| 62 |  | 
|---|
| 63 | SkRasterPipeline_MemoryCtx | 
|---|
| 64 | fDstPtr       = {nullptr,0},  // Always points to the top-left of fDst. | 
|---|
| 65 | fMaskPtr      = {nullptr,0};  // Updated each call to blitMask(). | 
|---|
| 66 | SkRasterPipeline_EmbossCtx fEmbossCtx;  // Used only for k3D_Format masks. | 
|---|
| 67 |  | 
|---|
| 68 | // We may be able to specialize blitH() or blitRect() into a memset. | 
|---|
| 69 | void   (*fMemset2D)(SkPixmap*, int x,int y, int w,int h, uint64_t color) = nullptr; | 
|---|
| 70 | uint64_t fMemsetColor = 0;   // Big enough for largest memsettable dst format, F16. | 
|---|
| 71 |  | 
|---|
| 72 | // Built lazily on first use. | 
|---|
| 73 | std::function<void(size_t, size_t, size_t, size_t)> fBlitRect, | 
|---|
| 74 | fBlitAntiH, | 
|---|
| 75 | fBlitMaskA8, | 
|---|
| 76 | fBlitMaskLCD16, | 
|---|
| 77 | fBlitMask3D; | 
|---|
| 78 |  | 
|---|
| 79 | // These values are pointed to by the blit pipelines above, | 
|---|
| 80 | // which allows us to adjust them from call to call. | 
|---|
| 81 | float fCurrentCoverage = 0.0f; | 
|---|
| 82 | float fDitherRate      = 0.0f; | 
|---|
| 83 |  | 
|---|
| 84 | typedef SkBlitter INHERITED; | 
|---|
| 85 | }; | 
|---|
| 86 |  | 
|---|
| 87 | SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst, | 
|---|
| 88 | const SkPaint& paint, | 
|---|
| 89 | const SkMatrix& ctm, | 
|---|
| 90 | SkArenaAlloc* alloc, | 
|---|
| 91 | sk_sp<SkShader> clipShader) { | 
|---|
| 92 | // For legacy to keep working, we need to sometimes still distinguish null dstCS from sRGB. | 
|---|
| 93 | #if 0 | 
|---|
| 94 | SkColorSpace* dstCS = dst.colorSpace() ? dst.colorSpace() | 
|---|
| 95 | : sk_srgb_singleton(); | 
|---|
| 96 | #else | 
|---|
| 97 | SkColorSpace* dstCS = dst.colorSpace(); | 
|---|
| 98 | #endif | 
|---|
| 99 | SkColorType dstCT = dst.colorType(); | 
|---|
| 100 | SkColor4f paintColor = paint.getColor4f(); | 
|---|
| 101 | SkColorSpaceXformSteps(sk_srgb_singleton(), kUnpremul_SkAlphaType, | 
|---|
| 102 | dstCS,               kUnpremul_SkAlphaType).apply(paintColor.vec()); | 
|---|
| 103 |  | 
|---|
| 104 | auto shader = as_SB(paint.getShader()); | 
|---|
| 105 |  | 
|---|
| 106 | SkRasterPipeline_<256> shaderPipeline; | 
|---|
| 107 | if (!shader) { | 
|---|
| 108 | // Having no shader makes things nice and easy... just use the paint color. | 
|---|
| 109 | shaderPipeline.append_constant_color(alloc, paintColor.premul().vec()); | 
|---|
| 110 | bool is_opaque    = paintColor.fA == 1.0f, | 
|---|
| 111 | is_constant  = true; | 
|---|
| 112 | return SkRasterPipelineBlitter::Create(dst, paint, alloc, | 
|---|
| 113 | shaderPipeline, is_opaque, is_constant, | 
|---|
| 114 | std::move(clipShader)); | 
|---|
| 115 | } | 
|---|
| 116 |  | 
|---|
| 117 | bool is_opaque    = shader->isOpaque() && paintColor.fA == 1.0f; | 
|---|
| 118 | bool is_constant  = shader->isConstant(); | 
|---|
| 119 |  | 
|---|
| 120 | if (shader->appendStages({&shaderPipeline, alloc, dstCT, dstCS, paint, nullptr, ctm})) { | 
|---|
| 121 | if (paintColor.fA != 1.0f) { | 
|---|
| 122 | shaderPipeline.append(SkRasterPipeline::scale_1_float, | 
|---|
| 123 | alloc->make<float>(paintColor.fA)); | 
|---|
| 124 | } | 
|---|
| 125 | return SkRasterPipelineBlitter::Create(dst, paint, alloc, | 
|---|
| 126 | shaderPipeline, is_opaque, is_constant, | 
|---|
| 127 | std::move(clipShader)); | 
|---|
| 128 | } | 
|---|
| 129 |  | 
|---|
| 130 | // The shader has opted out of drawing anything. | 
|---|
| 131 | return alloc->make<SkNullBlitter>(); | 
|---|
| 132 | } | 
|---|
| 133 |  | 
|---|
| 134 | SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst, | 
|---|
| 135 | const SkPaint& paint, | 
|---|
| 136 | const SkRasterPipeline& shaderPipeline, | 
|---|
| 137 | bool is_opaque, | 
|---|
| 138 | SkArenaAlloc* alloc, | 
|---|
| 139 | sk_sp<SkShader> clipShader) { | 
|---|
| 140 | bool is_constant = false;  // If this were the case, it'd be better to just set a paint color. | 
|---|
| 141 | return SkRasterPipelineBlitter::Create(dst, paint, alloc, | 
|---|
| 142 | shaderPipeline, is_opaque, is_constant, | 
|---|
| 143 | clipShader); | 
|---|
| 144 | } | 
|---|
| 145 |  | 
|---|
| 146 | SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst, | 
|---|
| 147 | const SkPaint& paint, | 
|---|
| 148 | SkArenaAlloc* alloc, | 
|---|
| 149 | const SkRasterPipeline& shaderPipeline, | 
|---|
| 150 | bool is_opaque, | 
|---|
| 151 | bool is_constant, | 
|---|
| 152 | sk_sp<SkShader> clipShader) { | 
|---|
| 153 | auto blitter = alloc->make<SkRasterPipelineBlitter>(dst, | 
|---|
| 154 | paint.getBlendMode(), | 
|---|
| 155 | alloc); | 
|---|
| 156 |  | 
|---|
| 157 |  | 
|---|
| 158 | // Our job in this factory is to fill out the blitter's color pipeline. | 
|---|
| 159 | // This is the common front of the full blit pipelines, each constructed lazily on first use. | 
|---|
| 160 | // The full blit pipelines handle reading and writing the dst, blending, coverage, dithering. | 
|---|
| 161 | auto colorPipeline = &blitter->fColorPipeline; | 
|---|
| 162 |  | 
|---|
| 163 | if (clipShader) { | 
|---|
| 164 | auto clipP = colorPipeline; | 
|---|
| 165 | SkPaint clipPaint;  // just need default values | 
|---|
| 166 | SkColorType clipCT = kRGBA_8888_SkColorType; | 
|---|
| 167 | SkColorSpace* clipCS = nullptr; | 
|---|
| 168 | SkMatrix clipM = SkMatrix::I(); | 
|---|
| 169 | SkStageRec rec = {clipP, alloc, clipCT, clipCS, clipPaint, nullptr, clipM}; | 
|---|
| 170 | if (as_SB(clipShader)->appendStages(rec)) { | 
|---|
| 171 | struct Storage { | 
|---|
| 172 | // large enough for highp (float) or lowp(U16) | 
|---|
| 173 | float   fA[SkRasterPipeline_kMaxStride]; | 
|---|
| 174 | }; | 
|---|
| 175 | auto storage = alloc->make<Storage>(); | 
|---|
| 176 | clipP->append(SkRasterPipeline::store_src_a, storage->fA); | 
|---|
| 177 | blitter->fClipShaderBuffer = storage->fA; | 
|---|
| 178 | is_constant = false; | 
|---|
| 179 | } | 
|---|
| 180 | } | 
|---|
| 181 |  | 
|---|
| 182 | // Let's get the shader in first. | 
|---|
| 183 | colorPipeline->extend(shaderPipeline); | 
|---|
| 184 |  | 
|---|
| 185 | // If there's a color filter it comes next. | 
|---|
| 186 | if (auto colorFilter = paint.getColorFilter()) { | 
|---|
| 187 | SkStageRec rec = { | 
|---|
| 188 | colorPipeline, alloc, dst.colorType(), dst.colorSpace(), paint, nullptr, SkMatrix::I() | 
|---|
| 189 | }; | 
|---|
| 190 | colorFilter->appendStages(rec, is_opaque); | 
|---|
| 191 | is_opaque = is_opaque && (colorFilter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag); | 
|---|
| 192 | } | 
|---|
| 193 |  | 
|---|
| 194 | // Not all formats make sense to dither (think, F16).  We set their dither rate | 
|---|
| 195 | // to zero.  We need to decide if we're going to dither now to keep is_constant accurate. | 
|---|
| 196 | if (paint.isDither()) { | 
|---|
| 197 | switch (dst.info().colorType()) { | 
|---|
| 198 | case kARGB_4444_SkColorType:    blitter->fDitherRate =   1/15.0f; break; | 
|---|
| 199 | case   kRGB_565_SkColorType:    blitter->fDitherRate =   1/63.0f; break; | 
|---|
| 200 | case    kGray_8_SkColorType: | 
|---|
| 201 | case  kRGB_888x_SkColorType: | 
|---|
| 202 | case kRGBA_8888_SkColorType: | 
|---|
| 203 | case kBGRA_8888_SkColorType:    blitter->fDitherRate =  1/255.0f; break; | 
|---|
| 204 | case kRGB_101010x_SkColorType: | 
|---|
| 205 | case kRGBA_1010102_SkColorType: | 
|---|
| 206 | case kBGR_101010x_SkColorType: | 
|---|
| 207 | case kBGRA_1010102_SkColorType: blitter->fDitherRate = 1/1023.0f; break; | 
|---|
| 208 |  | 
|---|
| 209 | case kUnknown_SkColorType: | 
|---|
| 210 | case kAlpha_8_SkColorType: | 
|---|
| 211 | case kRGBA_F16_SkColorType: | 
|---|
| 212 | case kRGBA_F16Norm_SkColorType: | 
|---|
| 213 | case kRGBA_F32_SkColorType: | 
|---|
| 214 | case kR8G8_unorm_SkColorType: | 
|---|
| 215 | case kA16_float_SkColorType: | 
|---|
| 216 | case kA16_unorm_SkColorType: | 
|---|
| 217 | case kR16G16_float_SkColorType: | 
|---|
| 218 | case kR16G16_unorm_SkColorType: | 
|---|
| 219 | case kR16G16B16A16_unorm_SkColorType: blitter->fDitherRate = 0.0f; break; | 
|---|
| 220 | } | 
|---|
| 221 | // TODO: for constant colors, we could try to measure the effect of dithering, and if | 
|---|
| 222 | //       it has no value (i.e. all variations result in the same 32bit color, then we | 
|---|
| 223 | //       could disable it (for speed, by not adding the stage). | 
|---|
| 224 | } | 
|---|
| 225 | is_constant = is_constant && (blitter->fDitherRate == 0.0f); | 
|---|
| 226 |  | 
|---|
| 227 | // We're logically done here.  The code between here and return blitter is all optimization. | 
|---|
| 228 |  | 
|---|
| 229 | // A pipeline that's still constant here can collapse back into a constant color. | 
|---|
| 230 | if (is_constant) { | 
|---|
| 231 | SkColor4f constantColor; | 
|---|
| 232 | SkRasterPipeline_MemoryCtx constantColorPtr = { &constantColor, 0 }; | 
|---|
| 233 | colorPipeline->append_gamut_clamp_if_normalized(dst.info()); | 
|---|
| 234 | colorPipeline->append(SkRasterPipeline::store_f32, &constantColorPtr); | 
|---|
| 235 | colorPipeline->run(0,0,1,1); | 
|---|
| 236 | colorPipeline->reset(); | 
|---|
| 237 | colorPipeline->append_constant_color(alloc, constantColor); | 
|---|
| 238 |  | 
|---|
| 239 | is_opaque = constantColor.fA == 1.0f; | 
|---|
| 240 | } | 
|---|
| 241 |  | 
|---|
| 242 | // We can strength-reduce SrcOver into Src when opaque. | 
|---|
| 243 | if (is_opaque && blitter->fBlend == SkBlendMode::kSrcOver) { | 
|---|
| 244 | blitter->fBlend = SkBlendMode::kSrc; | 
|---|
| 245 | } | 
|---|
| 246 |  | 
|---|
| 247 | // When we're drawing a constant color in Src mode, we can sometimes just memset. | 
|---|
| 248 | // (The previous two optimizations help find more opportunities for this one.) | 
|---|
| 249 | if (is_constant && blitter->fBlend == SkBlendMode::kSrc) { | 
|---|
| 250 | // Run our color pipeline all the way through to produce what we'd memset when we can. | 
|---|
| 251 | // Not all blits can memset, so we need to keep colorPipeline too. | 
|---|
| 252 | SkRasterPipeline_<256> p; | 
|---|
| 253 | p.extend(*colorPipeline); | 
|---|
| 254 | p.append_gamut_clamp_if_normalized(dst.info()); | 
|---|
| 255 | blitter->fDstPtr = SkRasterPipeline_MemoryCtx{&blitter->fMemsetColor, 0}; | 
|---|
| 256 | blitter->append_store(&p); | 
|---|
| 257 | p.run(0,0,1,1); | 
|---|
| 258 |  | 
|---|
| 259 | switch (blitter->fDst.shiftPerPixel()) { | 
|---|
| 260 | case 0: blitter->fMemset2D = [](SkPixmap* dst, int x,int y, int w,int h, uint64_t c) { | 
|---|
| 261 | void* p = dst->writable_addr(x,y); | 
|---|
| 262 | while (h --> 0) { | 
|---|
| 263 | memset(p, c, w); | 
|---|
| 264 | p = SkTAddOffset<void>(p, dst->rowBytes()); | 
|---|
| 265 | } | 
|---|
| 266 | }; break; | 
|---|
| 267 |  | 
|---|
| 268 | case 1: blitter->fMemset2D = [](SkPixmap* dst, int x,int y, int w,int h, uint64_t c) { | 
|---|
| 269 | SkOpts::rect_memset16(dst->writable_addr16(x,y), c, w, dst->rowBytes(), h); | 
|---|
| 270 | }; break; | 
|---|
| 271 |  | 
|---|
| 272 | case 2: blitter->fMemset2D = [](SkPixmap* dst, int x,int y, int w,int h, uint64_t c) { | 
|---|
| 273 | SkOpts::rect_memset32(dst->writable_addr32(x,y), c, w, dst->rowBytes(), h); | 
|---|
| 274 | }; break; | 
|---|
| 275 |  | 
|---|
| 276 | case 3: blitter->fMemset2D = [](SkPixmap* dst, int x,int y, int w,int h, uint64_t c) { | 
|---|
| 277 | SkOpts::rect_memset64(dst->writable_addr64(x,y), c, w, dst->rowBytes(), h); | 
|---|
| 278 | }; break; | 
|---|
| 279 |  | 
|---|
| 280 | // TODO(F32)? | 
|---|
| 281 | } | 
|---|
| 282 | } | 
|---|
| 283 |  | 
|---|
| 284 | blitter->fDstPtr = SkRasterPipeline_MemoryCtx{ | 
|---|
| 285 | blitter->fDst.writable_addr(), | 
|---|
| 286 | blitter->fDst.rowBytesAsPixels(), | 
|---|
| 287 | }; | 
|---|
| 288 |  | 
|---|
| 289 | return blitter; | 
|---|
| 290 | } | 
|---|
| 291 |  | 
|---|
| 292 | void SkRasterPipelineBlitter::append_load_dst(SkRasterPipeline* p) const { | 
|---|
| 293 | p->append_load_dst(fDst.info().colorType(), &fDstPtr); | 
|---|
| 294 | if (fDst.info().alphaType() == kUnpremul_SkAlphaType) { | 
|---|
| 295 | p->append(SkRasterPipeline::premul_dst); | 
|---|
| 296 | } | 
|---|
| 297 | } | 
|---|
| 298 |  | 
|---|
| 299 | void SkRasterPipelineBlitter::append_store(SkRasterPipeline* p) const { | 
|---|
| 300 | if (fDst.info().alphaType() == kUnpremul_SkAlphaType) { | 
|---|
| 301 | p->append(SkRasterPipeline::unpremul); | 
|---|
| 302 | } | 
|---|
| 303 | if (fDitherRate > 0.0f) { | 
|---|
| 304 | p->append(SkRasterPipeline::dither, &fDitherRate); | 
|---|
| 305 | } | 
|---|
| 306 |  | 
|---|
| 307 | p->append_store(fDst.info().colorType(), &fDstPtr); | 
|---|
| 308 | } | 
|---|
| 309 |  | 
|---|
| 310 | void SkRasterPipelineBlitter::append_clip_scale(SkRasterPipeline* p) const { | 
|---|
| 311 | if (fClipShaderBuffer) { | 
|---|
| 312 | p->append(SkRasterPipeline::scale_native, fClipShaderBuffer); | 
|---|
| 313 | } | 
|---|
| 314 | } | 
|---|
| 315 |  | 
|---|
| 316 | void SkRasterPipelineBlitter::append_clip_lerp(SkRasterPipeline* p) const { | 
|---|
| 317 | if (fClipShaderBuffer) { | 
|---|
| 318 | p->append(SkRasterPipeline::lerp_native, fClipShaderBuffer); | 
|---|
| 319 | } | 
|---|
| 320 | } | 
|---|
| 321 |  | 
|---|
| 322 | void SkRasterPipelineBlitter::blitH(int x, int y, int w) { | 
|---|
| 323 | this->blitRect(x,y,w,1); | 
|---|
| 324 | } | 
|---|
| 325 |  | 
|---|
| 326 | void SkRasterPipelineBlitter::blitRect(int x, int y, int w, int h) { | 
|---|
| 327 | if (fMemset2D) { | 
|---|
| 328 | fMemset2D(&fDst, x,y, w,h, fMemsetColor); | 
|---|
| 329 | return; | 
|---|
| 330 | } | 
|---|
| 331 |  | 
|---|
| 332 | if (!fBlitRect) { | 
|---|
| 333 | SkRasterPipeline p(fAlloc); | 
|---|
| 334 | p.extend(fColorPipeline); | 
|---|
| 335 | p.append_gamut_clamp_if_normalized(fDst.info()); | 
|---|
| 336 | if (fBlend == SkBlendMode::kSrcOver | 
|---|
| 337 | && (fDst.info().colorType() == kRGBA_8888_SkColorType || | 
|---|
| 338 | fDst.info().colorType() == kBGRA_8888_SkColorType) | 
|---|
| 339 | && !fDst.colorSpace() | 
|---|
| 340 | && fDst.info().alphaType() != kUnpremul_SkAlphaType | 
|---|
| 341 | && fDitherRate == 0.0f) { | 
|---|
| 342 | if (fDst.info().colorType() == kBGRA_8888_SkColorType) { | 
|---|
| 343 | p.append(SkRasterPipeline::swap_rb); | 
|---|
| 344 | } | 
|---|
| 345 | this->append_clip_scale(&p); | 
|---|
| 346 | p.append(SkRasterPipeline::srcover_rgba_8888, &fDstPtr); | 
|---|
| 347 | } else { | 
|---|
| 348 | if (fBlend != SkBlendMode::kSrc) { | 
|---|
| 349 | this->append_load_dst(&p); | 
|---|
| 350 | SkBlendMode_AppendStages(fBlend, &p); | 
|---|
| 351 | this->append_clip_lerp(&p); | 
|---|
| 352 | } else if (fClipShaderBuffer) { | 
|---|
| 353 | this->append_load_dst(&p); | 
|---|
| 354 | this->append_clip_lerp(&p); | 
|---|
| 355 | } | 
|---|
| 356 | this->append_store(&p); | 
|---|
| 357 | } | 
|---|
| 358 | fBlitRect = p.compile(); | 
|---|
| 359 | } | 
|---|
| 360 |  | 
|---|
| 361 | fBlitRect(x,y,w,h); | 
|---|
| 362 | } | 
|---|
| 363 |  | 
|---|
| 364 | void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) { | 
|---|
| 365 | if (!fBlitAntiH) { | 
|---|
| 366 | SkRasterPipeline p(fAlloc); | 
|---|
| 367 | p.extend(fColorPipeline); | 
|---|
| 368 | p.append_gamut_clamp_if_normalized(fDst.info()); | 
|---|
| 369 | if (SkBlendMode_ShouldPreScaleCoverage(fBlend, /*rgb_coverage=*/false)) { | 
|---|
| 370 | p.append(SkRasterPipeline::scale_1_float, &fCurrentCoverage); | 
|---|
| 371 | this->append_clip_scale(&p); | 
|---|
| 372 | this->append_load_dst(&p); | 
|---|
| 373 | SkBlendMode_AppendStages(fBlend, &p); | 
|---|
| 374 | } else { | 
|---|
| 375 | this->append_load_dst(&p); | 
|---|
| 376 | SkBlendMode_AppendStages(fBlend, &p); | 
|---|
| 377 | p.append(SkRasterPipeline::lerp_1_float, &fCurrentCoverage); | 
|---|
| 378 | this->append_clip_lerp(&p); | 
|---|
| 379 | } | 
|---|
| 380 |  | 
|---|
| 381 | this->append_store(&p); | 
|---|
| 382 | fBlitAntiH = p.compile(); | 
|---|
| 383 | } | 
|---|
| 384 |  | 
|---|
| 385 | for (int16_t run = *runs; run > 0; run = *runs) { | 
|---|
| 386 | switch (*aa) { | 
|---|
| 387 | case 0x00:                       break; | 
|---|
| 388 | case 0xff: this->blitH(x,y,run); break; | 
|---|
| 389 | default: | 
|---|
| 390 | fCurrentCoverage = *aa * (1/255.0f); | 
|---|
| 391 | fBlitAntiH(x,y,run,1); | 
|---|
| 392 | } | 
|---|
| 393 | x    += run; | 
|---|
| 394 | runs += run; | 
|---|
| 395 | aa   += run; | 
|---|
| 396 | } | 
|---|
| 397 | } | 
|---|
| 398 |  | 
|---|
| 399 | void SkRasterPipelineBlitter::blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) { | 
|---|
| 400 | SkIRect clip = {x,y, x+2,y+1}; | 
|---|
| 401 | uint8_t coverage[] = { (uint8_t)a0, (uint8_t)a1 }; | 
|---|
| 402 |  | 
|---|
| 403 | SkMask mask; | 
|---|
| 404 | mask.fImage    = coverage; | 
|---|
| 405 | mask.fBounds   = clip; | 
|---|
| 406 | mask.fRowBytes = 2; | 
|---|
| 407 | mask.fFormat   = SkMask::kA8_Format; | 
|---|
| 408 |  | 
|---|
| 409 | this->blitMask(mask, clip); | 
|---|
| 410 | } | 
|---|
| 411 |  | 
|---|
| 412 | void SkRasterPipelineBlitter::blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) { | 
|---|
| 413 | SkIRect clip = {x,y, x+1,y+2}; | 
|---|
| 414 | uint8_t coverage[] = { (uint8_t)a0, (uint8_t)a1 }; | 
|---|
| 415 |  | 
|---|
| 416 | SkMask mask; | 
|---|
| 417 | mask.fImage    = coverage; | 
|---|
| 418 | mask.fBounds   = clip; | 
|---|
| 419 | mask.fRowBytes = 1; | 
|---|
| 420 | mask.fFormat   = SkMask::kA8_Format; | 
|---|
| 421 |  | 
|---|
| 422 | this->blitMask(mask, clip); | 
|---|
| 423 | } | 
|---|
| 424 |  | 
|---|
| 425 | void SkRasterPipelineBlitter::blitV(int x, int y, int height, SkAlpha alpha) { | 
|---|
| 426 | SkIRect clip = {x,y, x+1,y+height}; | 
|---|
| 427 |  | 
|---|
| 428 | SkMask mask; | 
|---|
| 429 | mask.fImage    = α | 
|---|
| 430 | mask.fBounds   = clip; | 
|---|
| 431 | mask.fRowBytes = 0;     // so we reuse the 1 "row" for all of height | 
|---|
| 432 | mask.fFormat   = SkMask::kA8_Format; | 
|---|
| 433 |  | 
|---|
| 434 | this->blitMask(mask, clip); | 
|---|
| 435 | } | 
|---|
| 436 |  | 
|---|
| 437 | void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) { | 
|---|
| 438 | if (mask.fFormat == SkMask::kBW_Format) { | 
|---|
| 439 | // TODO: native BW masks? | 
|---|
| 440 | return INHERITED::blitMask(mask, clip); | 
|---|
| 441 | } | 
|---|
| 442 |  | 
|---|
| 443 | // ARGB and SDF masks shouldn't make it here. | 
|---|
| 444 | SkASSERT(mask.fFormat == SkMask::kA8_Format | 
|---|
| 445 | || mask.fFormat == SkMask::kLCD16_Format | 
|---|
| 446 | || mask.fFormat == SkMask::k3D_Format); | 
|---|
| 447 |  | 
|---|
| 448 | auto  = [&mask](int plane, SkRasterPipeline_MemoryCtx* ctx) { | 
|---|
| 449 | // LCD is 16-bit per pixel; A8 and 3D are 8-bit per pixel. | 
|---|
| 450 | size_t bpp = mask.fFormat == SkMask::kLCD16_Format ? 2 : 1; | 
|---|
| 451 |  | 
|---|
| 452 | // Select the right mask plane.  Usually plane == 0 and this is just mask.fImage. | 
|---|
| 453 | auto ptr = (uintptr_t)mask.fImage | 
|---|
| 454 | + plane * mask.computeImageSize(); | 
|---|
| 455 |  | 
|---|
| 456 | // Update ctx to point "into" this current mask, but lined up with fDstPtr at (0,0). | 
|---|
| 457 | // This sort of trickery upsets UBSAN (pointer-overflow) so our ptr must be a uintptr_t. | 
|---|
| 458 | // mask.fRowBytes is a uint32_t, which would break our addressing math on 64-bit builds. | 
|---|
| 459 | size_t rowBytes = mask.fRowBytes; | 
|---|
| 460 | ctx->stride = rowBytes / bpp; | 
|---|
| 461 | ctx->pixels = (void*)(ptr - mask.fBounds.left() * bpp | 
|---|
| 462 | - mask.fBounds.top()  * rowBytes); | 
|---|
| 463 | }; | 
|---|
| 464 |  | 
|---|
| 465 | extract_mask_plane(0, &fMaskPtr); | 
|---|
| 466 | if (mask.fFormat == SkMask::k3D_Format) { | 
|---|
| 467 | extract_mask_plane(1, &fEmbossCtx.mul); | 
|---|
| 468 | extract_mask_plane(2, &fEmbossCtx.add); | 
|---|
| 469 | } | 
|---|
| 470 |  | 
|---|
| 471 | // Lazily build whichever pipeline we need, specialized for each mask format. | 
|---|
| 472 | if (mask.fFormat == SkMask::kA8_Format && !fBlitMaskA8) { | 
|---|
| 473 | SkRasterPipeline p(fAlloc); | 
|---|
| 474 | p.extend(fColorPipeline); | 
|---|
| 475 | p.append_gamut_clamp_if_normalized(fDst.info()); | 
|---|
| 476 | if (SkBlendMode_ShouldPreScaleCoverage(fBlend, /*rgb_coverage=*/false)) { | 
|---|
| 477 | p.append(SkRasterPipeline::scale_u8, &fMaskPtr); | 
|---|
| 478 | this->append_clip_scale(&p); | 
|---|
| 479 | this->append_load_dst(&p); | 
|---|
| 480 | SkBlendMode_AppendStages(fBlend, &p); | 
|---|
| 481 | } else { | 
|---|
| 482 | this->append_load_dst(&p); | 
|---|
| 483 | SkBlendMode_AppendStages(fBlend, &p); | 
|---|
| 484 | p.append(SkRasterPipeline::lerp_u8, &fMaskPtr); | 
|---|
| 485 | this->append_clip_lerp(&p); | 
|---|
| 486 | } | 
|---|
| 487 | this->append_store(&p); | 
|---|
| 488 | fBlitMaskA8 = p.compile(); | 
|---|
| 489 | } | 
|---|
| 490 | if (mask.fFormat == SkMask::kLCD16_Format && !fBlitMaskLCD16) { | 
|---|
| 491 | SkRasterPipeline p(fAlloc); | 
|---|
| 492 | p.extend(fColorPipeline); | 
|---|
| 493 | p.append_gamut_clamp_if_normalized(fDst.info()); | 
|---|
| 494 | if (SkBlendMode_ShouldPreScaleCoverage(fBlend, /*rgb_coverage=*/true)) { | 
|---|
| 495 | // Somewhat unusually, scale_565 needs dst loaded first. | 
|---|
| 496 | this->append_load_dst(&p); | 
|---|
| 497 | p.append(SkRasterPipeline::scale_565, &fMaskPtr); | 
|---|
| 498 | this->append_clip_scale(&p); | 
|---|
| 499 | SkBlendMode_AppendStages(fBlend, &p); | 
|---|
| 500 | } else { | 
|---|
| 501 | this->append_load_dst(&p); | 
|---|
| 502 | SkBlendMode_AppendStages(fBlend, &p); | 
|---|
| 503 | p.append(SkRasterPipeline::lerp_565, &fMaskPtr); | 
|---|
| 504 | this->append_clip_lerp(&p); | 
|---|
| 505 | } | 
|---|
| 506 | this->append_store(&p); | 
|---|
| 507 | fBlitMaskLCD16 = p.compile(); | 
|---|
| 508 | } | 
|---|
| 509 | if (mask.fFormat == SkMask::k3D_Format && !fBlitMask3D) { | 
|---|
| 510 | SkRasterPipeline p(fAlloc); | 
|---|
| 511 | p.extend(fColorPipeline); | 
|---|
| 512 | // This bit is where we differ from kA8_Format: | 
|---|
| 513 | p.append(SkRasterPipeline::emboss, &fEmbossCtx); | 
|---|
| 514 | // Now onward just as kA8. | 
|---|
| 515 | p.append_gamut_clamp_if_normalized(fDst.info()); | 
|---|
| 516 | if (SkBlendMode_ShouldPreScaleCoverage(fBlend, /*rgb_coverage=*/false)) { | 
|---|
| 517 | p.append(SkRasterPipeline::scale_u8, &fMaskPtr); | 
|---|
| 518 | this->append_clip_scale(&p); | 
|---|
| 519 | this->append_load_dst(&p); | 
|---|
| 520 | SkBlendMode_AppendStages(fBlend, &p); | 
|---|
| 521 | } else { | 
|---|
| 522 | this->append_load_dst(&p); | 
|---|
| 523 | SkBlendMode_AppendStages(fBlend, &p); | 
|---|
| 524 | p.append(SkRasterPipeline::lerp_u8, &fMaskPtr); | 
|---|
| 525 | this->append_clip_lerp(&p); | 
|---|
| 526 | } | 
|---|
| 527 | this->append_store(&p); | 
|---|
| 528 | fBlitMask3D = p.compile(); | 
|---|
| 529 | } | 
|---|
| 530 |  | 
|---|
| 531 | std::function<void(size_t,size_t,size_t,size_t)>* blitter = nullptr; | 
|---|
| 532 | switch (mask.fFormat) { | 
|---|
| 533 | case SkMask::kA8_Format:    blitter = &fBlitMaskA8;    break; | 
|---|
| 534 | case SkMask::kLCD16_Format: blitter = &fBlitMaskLCD16; break; | 
|---|
| 535 | case SkMask::k3D_Format:    blitter = &fBlitMask3D;    break; | 
|---|
| 536 | default: | 
|---|
| 537 | SkASSERT(false); | 
|---|
| 538 | return; | 
|---|
| 539 | } | 
|---|
| 540 |  | 
|---|
| 541 | SkASSERT(blitter); | 
|---|
| 542 | (*blitter)(clip.left(),clip.top(), clip.width(),clip.height()); | 
|---|
| 543 | } | 
|---|
| 544 |  | 
|---|