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