1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2006 The Android Open Source Project 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/SkColorSpace.h" 9cb93a386Sopenharmony_ci#include "src/core/SkArenaAlloc.h" 10cb93a386Sopenharmony_ci#include "src/core/SkColorSpacePriv.h" 11cb93a386Sopenharmony_ci#include "src/core/SkColorSpaceXformSteps.h" 12cb93a386Sopenharmony_ci#include "src/core/SkCoreBlitters.h" 13cb93a386Sopenharmony_ci#include "src/core/SkOpts.h" 14cb93a386Sopenharmony_ci#include "src/core/SkRasterPipeline.h" 15cb93a386Sopenharmony_ci#include "src/core/SkSpriteBlitter.h" 16cb93a386Sopenharmony_ci#include "src/core/SkVMBlitter.h" 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_ciextern bool gUseSkVMBlitter; 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_ciSkSpriteBlitter::SkSpriteBlitter(const SkPixmap& source) 21cb93a386Sopenharmony_ci : fSource(source) {} 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_cibool SkSpriteBlitter::setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) { 24cb93a386Sopenharmony_ci fDst = dst; 25cb93a386Sopenharmony_ci fLeft = left; 26cb93a386Sopenharmony_ci fTop = top; 27cb93a386Sopenharmony_ci fPaint = &paint; 28cb93a386Sopenharmony_ci return true; 29cb93a386Sopenharmony_ci} 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_civoid SkSpriteBlitter::blitH(int x, int y, int width) { 32cb93a386Sopenharmony_ci SkDEBUGFAIL("how did we get here?"); 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ci // Fallback to blitRect. 35cb93a386Sopenharmony_ci this->blitRect(x, y, width, 1); 36cb93a386Sopenharmony_ci} 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_civoid SkSpriteBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) { 39cb93a386Sopenharmony_ci SkDEBUGFAIL("how did we get here?"); 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci // No fallback strategy. 42cb93a386Sopenharmony_ci} 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_civoid SkSpriteBlitter::blitV(int x, int y, int height, SkAlpha alpha) { 45cb93a386Sopenharmony_ci SkDEBUGFAIL("how did we get here?"); 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci // Fall back to superclass if the code gets here in release mode. 48cb93a386Sopenharmony_ci INHERITED::blitV(x, y, height, alpha); 49cb93a386Sopenharmony_ci} 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_civoid SkSpriteBlitter::blitMask(const SkMask& mask, const SkIRect& clip) { 52cb93a386Sopenharmony_ci SkDEBUGFAIL("how did we get here?"); 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ci // Fall back to superclass if the code gets here in release mode. 55cb93a386Sopenharmony_ci INHERITED::blitMask(mask, clip); 56cb93a386Sopenharmony_ci} 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 59cb93a386Sopenharmony_ci 60cb93a386Sopenharmony_ciclass SkSpriteBlitter_Memcpy final : public SkSpriteBlitter { 61cb93a386Sopenharmony_cipublic: 62cb93a386Sopenharmony_ci static bool Supports(const SkPixmap& dst, const SkPixmap& src, const SkPaint& paint) { 63cb93a386Sopenharmony_ci // the caller has already inspected the colorspace on src and dst 64cb93a386Sopenharmony_ci SkASSERT(0 == SkColorSpaceXformSteps(src,dst).flags.mask()); 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_ci if (dst.colorType() != src.colorType()) { 67cb93a386Sopenharmony_ci return false; 68cb93a386Sopenharmony_ci } 69cb93a386Sopenharmony_ci if (paint.getMaskFilter() || paint.getColorFilter() || paint.getImageFilter()) { 70cb93a386Sopenharmony_ci return false; 71cb93a386Sopenharmony_ci } 72cb93a386Sopenharmony_ci if (0xFF != paint.getAlpha()) { 73cb93a386Sopenharmony_ci return false; 74cb93a386Sopenharmony_ci } 75cb93a386Sopenharmony_ci const auto mode = paint.asBlendMode(); 76cb93a386Sopenharmony_ci return mode == SkBlendMode::kSrc || (mode == SkBlendMode::kSrcOver && src.isOpaque()); 77cb93a386Sopenharmony_ci } 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_ci SkSpriteBlitter_Memcpy(const SkPixmap& src) 80cb93a386Sopenharmony_ci : INHERITED(src) {} 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_ci void blitRect(int x, int y, int width, int height) override { 83cb93a386Sopenharmony_ci SkASSERT(fDst.colorType() == fSource.colorType()); 84cb93a386Sopenharmony_ci SkASSERT(width > 0 && height > 0); 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_ci char* dst = (char*)fDst.writable_addr(x, y); 87cb93a386Sopenharmony_ci const char* src = (const char*)fSource.addr(x - fLeft, y - fTop); 88cb93a386Sopenharmony_ci const size_t dstRB = fDst.rowBytes(); 89cb93a386Sopenharmony_ci const size_t srcRB = fSource.rowBytes(); 90cb93a386Sopenharmony_ci const size_t bytesToCopy = width << fSource.shiftPerPixel(); 91cb93a386Sopenharmony_ci 92cb93a386Sopenharmony_ci while (height --> 0) { 93cb93a386Sopenharmony_ci memcpy(dst, src, bytesToCopy); 94cb93a386Sopenharmony_ci dst += dstRB; 95cb93a386Sopenharmony_ci src += srcRB; 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci } 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ciprivate: 100cb93a386Sopenharmony_ci using INHERITED = SkSpriteBlitter; 101cb93a386Sopenharmony_ci}; 102cb93a386Sopenharmony_ci 103cb93a386Sopenharmony_ciclass SkRasterPipelineSpriteBlitter : public SkSpriteBlitter { 104cb93a386Sopenharmony_cipublic: 105cb93a386Sopenharmony_ci SkRasterPipelineSpriteBlitter(const SkPixmap& src, SkArenaAlloc* alloc, 106cb93a386Sopenharmony_ci sk_sp<SkShader> clipShader) 107cb93a386Sopenharmony_ci : INHERITED(src) 108cb93a386Sopenharmony_ci , fAlloc(alloc) 109cb93a386Sopenharmony_ci , fBlitter(nullptr) 110cb93a386Sopenharmony_ci , fSrcPtr{nullptr, 0} 111cb93a386Sopenharmony_ci , fClipShader(std::move(clipShader)) 112cb93a386Sopenharmony_ci {} 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_ci bool setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override { 115cb93a386Sopenharmony_ci fDst = dst; 116cb93a386Sopenharmony_ci fLeft = left; 117cb93a386Sopenharmony_ci fTop = top; 118cb93a386Sopenharmony_ci fPaintColor = paint.getColor4f(); 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_ci SkRasterPipeline p(fAlloc); 121cb93a386Sopenharmony_ci p.append_load(fSource.colorType(), &fSrcPtr); 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci if (fSource.colorType() == kAlpha_8_SkColorType) { 124cb93a386Sopenharmony_ci // The color for A8 images comes from the (sRGB) paint color. 125cb93a386Sopenharmony_ci p.append_set_rgb(fAlloc, fPaintColor); 126cb93a386Sopenharmony_ci p.append(SkRasterPipeline::premul); 127cb93a386Sopenharmony_ci } 128cb93a386Sopenharmony_ci if (auto dstCS = fDst.colorSpace()) { 129cb93a386Sopenharmony_ci auto srcCS = fSource.colorSpace(); 130cb93a386Sopenharmony_ci if (!srcCS || fSource.colorType() == kAlpha_8_SkColorType) { 131cb93a386Sopenharmony_ci // We treat untagged images as sRGB. 132cb93a386Sopenharmony_ci // A8 images get their r,g,b from the paint color, so they're also sRGB. 133cb93a386Sopenharmony_ci srcCS = sk_srgb_singleton(); 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci auto srcAT = fSource.isOpaque() ? kOpaque_SkAlphaType 136cb93a386Sopenharmony_ci : kPremul_SkAlphaType; 137cb93a386Sopenharmony_ci fAlloc->make<SkColorSpaceXformSteps>(srcCS, srcAT, 138cb93a386Sopenharmony_ci dstCS, kPremul_SkAlphaType) 139cb93a386Sopenharmony_ci ->apply(&p); 140cb93a386Sopenharmony_ci } 141cb93a386Sopenharmony_ci if (fPaintColor.fA != 1.0f) { 142cb93a386Sopenharmony_ci p.append(SkRasterPipeline::scale_1_float, &fPaintColor.fA); 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci bool is_opaque = fSource.isOpaque() && fPaintColor.fA == 1.0f; 146cb93a386Sopenharmony_ci fBlitter = SkCreateRasterPipelineBlitter(fDst, paint, p, is_opaque, fAlloc, fClipShader); 147cb93a386Sopenharmony_ci return fBlitter != nullptr; 148cb93a386Sopenharmony_ci } 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_ci void blitRect(int x, int y, int width, int height) override { 151cb93a386Sopenharmony_ci fSrcPtr.stride = fSource.rowBytesAsPixels(); 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci // We really want fSrcPtr.pixels = fSource.addr(-fLeft, -fTop) here, but that asserts. 154cb93a386Sopenharmony_ci // Instead we ask for addr(-fLeft+x, -fTop+y), then back up (x,y) manually. 155cb93a386Sopenharmony_ci // Representing bpp as a size_t keeps all this math in size_t instead of int, 156cb93a386Sopenharmony_ci // which could wrap around with large enough fSrcPtr.stride and y. 157cb93a386Sopenharmony_ci size_t bpp = fSource.info().bytesPerPixel(); 158cb93a386Sopenharmony_ci fSrcPtr.pixels = (char*)fSource.addr(-fLeft+x, -fTop+y) - bpp * x 159cb93a386Sopenharmony_ci - bpp * y * fSrcPtr.stride; 160cb93a386Sopenharmony_ci 161cb93a386Sopenharmony_ci fBlitter->blitRect(x,y,width,height); 162cb93a386Sopenharmony_ci } 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_ciprivate: 165cb93a386Sopenharmony_ci SkArenaAlloc* fAlloc; 166cb93a386Sopenharmony_ci SkBlitter* fBlitter; 167cb93a386Sopenharmony_ci SkRasterPipeline_MemoryCtx fSrcPtr; 168cb93a386Sopenharmony_ci SkColor4f fPaintColor; 169cb93a386Sopenharmony_ci sk_sp<SkShader> fClipShader; 170cb93a386Sopenharmony_ci 171cb93a386Sopenharmony_ci using INHERITED = SkSpriteBlitter; 172cb93a386Sopenharmony_ci}; 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ci// returning null means the caller will call SkBlitter::Choose() and 175cb93a386Sopenharmony_ci// have wrapped the source bitmap inside a shader 176cb93a386Sopenharmony_ciSkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint, 177cb93a386Sopenharmony_ci const SkPixmap& source, int left, int top, 178cb93a386Sopenharmony_ci SkArenaAlloc* alloc, sk_sp<SkShader> clipShader) { 179cb93a386Sopenharmony_ci /* We currently ignore antialiasing and filtertype, meaning we will take our 180cb93a386Sopenharmony_ci special blitters regardless of these settings. Ignoring filtertype seems fine 181cb93a386Sopenharmony_ci since by definition there is no scale in the matrix. Ignoring antialiasing is 182cb93a386Sopenharmony_ci a bit of a hack, since we "could" pass in the fractional left/top for the bitmap, 183cb93a386Sopenharmony_ci and respect that by blending the edges of the bitmap against the device. To support 184cb93a386Sopenharmony_ci this we could either add more special blitters here, or detect antialiasing in the 185cb93a386Sopenharmony_ci paint and return null if it is set, forcing the client to take the slow shader case 186cb93a386Sopenharmony_ci (which does respect soft edges). 187cb93a386Sopenharmony_ci */ 188cb93a386Sopenharmony_ci SkASSERT(alloc != nullptr); 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci if (gUseSkVMBlitter) { 191cb93a386Sopenharmony_ci return SkVMBlitter::Make(dst, paint, source,left,top, alloc, std::move(clipShader)); 192cb93a386Sopenharmony_ci } 193cb93a386Sopenharmony_ci 194cb93a386Sopenharmony_ci // TODO: in principle SkRasterPipelineSpriteBlitter could be made to handle this. 195cb93a386Sopenharmony_ci if (source.alphaType() == kUnpremul_SkAlphaType) { 196cb93a386Sopenharmony_ci return nullptr; 197cb93a386Sopenharmony_ci } 198cb93a386Sopenharmony_ci 199cb93a386Sopenharmony_ci SkSpriteBlitter* blitter = nullptr; 200cb93a386Sopenharmony_ci 201cb93a386Sopenharmony_ci if (0 == SkColorSpaceXformSteps(source,dst).flags.mask() && !clipShader) { 202cb93a386Sopenharmony_ci if (!blitter && SkSpriteBlitter_Memcpy::Supports(dst, source, paint)) { 203cb93a386Sopenharmony_ci blitter = alloc->make<SkSpriteBlitter_Memcpy>(source); 204cb93a386Sopenharmony_ci } 205cb93a386Sopenharmony_ci if (!blitter) { 206cb93a386Sopenharmony_ci switch (dst.colorType()) { 207cb93a386Sopenharmony_ci case kN32_SkColorType: 208cb93a386Sopenharmony_ci blitter = SkSpriteBlitter::ChooseL32(source, paint, alloc); 209cb93a386Sopenharmony_ci break; 210cb93a386Sopenharmony_ci case kRGB_565_SkColorType: 211cb93a386Sopenharmony_ci blitter = SkSpriteBlitter::ChooseL565(source, paint, alloc); 212cb93a386Sopenharmony_ci break; 213cb93a386Sopenharmony_ci case kAlpha_8_SkColorType: 214cb93a386Sopenharmony_ci blitter = SkSpriteBlitter::ChooseLA8(source, paint, alloc); 215cb93a386Sopenharmony_ci break; 216cb93a386Sopenharmony_ci default: 217cb93a386Sopenharmony_ci break; 218cb93a386Sopenharmony_ci } 219cb93a386Sopenharmony_ci } 220cb93a386Sopenharmony_ci } 221cb93a386Sopenharmony_ci if (!blitter && !paint.getMaskFilter()) { 222cb93a386Sopenharmony_ci blitter = alloc->make<SkRasterPipelineSpriteBlitter>(source, alloc, clipShader); 223cb93a386Sopenharmony_ci } 224cb93a386Sopenharmony_ci 225cb93a386Sopenharmony_ci if (blitter && blitter->setup(dst, left,top, paint)) { 226cb93a386Sopenharmony_ci return blitter; 227cb93a386Sopenharmony_ci } 228cb93a386Sopenharmony_ci 229cb93a386Sopenharmony_ci return SkVMBlitter::Make(dst, paint, source,left,top, alloc, std::move(clipShader)); 230cb93a386Sopenharmony_ci} 231