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