Line data Source code
1 : /*
2 : * Copyright 2006 The Android Open Source Project
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 "SkArenaAlloc.h"
9 : #include "SkOpts.h"
10 : #include "SkSpriteBlitter.h"
11 :
12 118 : SkSpriteBlitter::SkSpriteBlitter(const SkPixmap& source)
13 118 : : fSource(source) {}
14 :
15 118 : void SkSpriteBlitter::setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) {
16 118 : fDst = dst;
17 118 : fLeft = left;
18 118 : fTop = top;
19 118 : fPaint = &paint;
20 118 : }
21 :
22 0 : void SkSpriteBlitter::blitH(int x, int y, int width) {
23 0 : SkDEBUGFAIL("how did we get here?");
24 :
25 : // Fallback to blitRect.
26 0 : this->blitRect(x, y, width, 1);
27 0 : }
28 :
29 0 : void SkSpriteBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) {
30 0 : SkDEBUGFAIL("how did we get here?");
31 :
32 : // No fallback strategy.
33 0 : }
34 :
35 0 : void SkSpriteBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
36 0 : SkDEBUGFAIL("how did we get here?");
37 :
38 : // Fall back to superclass if the code gets here in release mode.
39 0 : INHERITED::blitV(x, y, height, alpha);
40 0 : }
41 :
42 0 : void SkSpriteBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
43 0 : SkDEBUGFAIL("how did we get here?");
44 :
45 : // Fall back to superclass if the code gets here in release mode.
46 0 : INHERITED::blitMask(mask, clip);
47 0 : }
48 :
49 : ///////////////////////////////////////////////////////////////////////////////
50 :
51 : // Only valid if...
52 : // 1. src == dst format
53 : // 2. paint has no modifiers (i.e. alpha, colorfilter, etc.)
54 : // 3. xfermode needs no blending: e.g. kSrc_Mode or kSrcOver_Mode + opaque src
55 : //
56 17 : class SkSpriteBlitter_Src_SrcOver final : public SkSpriteBlitter {
57 : public:
58 135 : static bool Supports(const SkPixmap& dst, const SkPixmap& src, const SkPaint& paint) {
59 135 : if (dst.colorType() != src.colorType()) {
60 0 : return false;
61 : }
62 135 : if (dst.info().gammaCloseToSRGB() != src.info().gammaCloseToSRGB()) {
63 0 : return false;
64 : }
65 135 : if (paint.getMaskFilter() || paint.getColorFilter() || paint.getImageFilter()) {
66 0 : return false;
67 : }
68 135 : if (0xFF != paint.getAlpha()) {
69 11 : return false;
70 : }
71 124 : SkBlendMode mode = paint.getBlendMode();
72 124 : if (SkBlendMode::kSrc == mode) {
73 28 : return true;
74 : }
75 96 : if (SkBlendMode::kSrcOver == mode && src.isOpaque()) {
76 6 : return true;
77 : }
78 :
79 : // At this point memcpy can't be used. The following check for using SrcOver.
80 :
81 90 : if (dst.colorType() != kN32_SkColorType || !dst.info().gammaCloseToSRGB()) {
82 90 : return false;
83 : }
84 :
85 0 : return SkBlendMode::kSrcOver == mode;
86 : }
87 :
88 17 : SkSpriteBlitter_Src_SrcOver(const SkPixmap& src)
89 17 : : INHERITED(src) {}
90 :
91 17 : void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override {
92 17 : SkASSERT(Supports(dst, fSource, paint));
93 17 : this->INHERITED::setup(dst, left, top, paint);
94 17 : SkBlendMode mode = paint.getBlendMode();
95 :
96 17 : SkASSERT(mode == SkBlendMode::kSrcOver || mode == SkBlendMode::kSrc);
97 :
98 17 : if (mode == SkBlendMode::kSrcOver && !fSource.isOpaque()) {
99 0 : fUseMemcpy = false;
100 : }
101 17 : }
102 :
103 17 : void blitRect(int x, int y, int width, int height) override {
104 17 : SkASSERT(fDst.colorType() == fSource.colorType());
105 17 : SkASSERT(fDst.info().gammaCloseToSRGB() == fSource.info().gammaCloseToSRGB());
106 17 : SkASSERT(width > 0 && height > 0);
107 :
108 17 : if (fUseMemcpy) {
109 17 : char* dst = (char*)fDst.writable_addr(x, y);
110 17 : const char* src = (const char*)fSource.addr(x - fLeft, y - fTop);
111 17 : const size_t dstRB = fDst.rowBytes();
112 17 : const size_t srcRB = fSource.rowBytes();
113 17 : const size_t bytesToCopy = width << fSource.shiftPerPixel();
114 :
115 10533 : while (height --> 0) {
116 5258 : memcpy(dst, src, bytesToCopy);
117 5258 : dst += dstRB;
118 5258 : src += srcRB;
119 : }
120 : } else {
121 0 : uint32_t* dst = fDst.writable_addr32(x, y);
122 0 : const uint32_t* src = fSource.addr32(x - fLeft, y - fTop);
123 0 : const int dstStride = fDst.rowBytesAsPixels();
124 0 : const int srcStride = fSource.rowBytesAsPixels();
125 :
126 0 : while (height --> 0) {
127 0 : SkOpts::srcover_srgb_srgb(dst, src, width, width);
128 0 : dst += dstStride;
129 0 : src += srcStride;
130 : }
131 : }
132 17 : }
133 :
134 : private:
135 : typedef SkSpriteBlitter INHERITED;
136 :
137 : bool fUseMemcpy {true};
138 : };
139 :
140 : // returning null means the caller will call SkBlitter::Choose() and
141 : // have wrapped the source bitmap inside a shader
142 118 : SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint,
143 : const SkPixmap& source, int left, int top, SkArenaAlloc* allocator) {
144 : /* We currently ignore antialiasing and filtertype, meaning we will take our
145 : special blitters regardless of these settings. Ignoring filtertype seems fine
146 : since by definition there is no scale in the matrix. Ignoring antialiasing is
147 : a bit of a hack, since we "could" pass in the fractional left/top for the bitmap,
148 : and respect that by blending the edges of the bitmap against the device. To support
149 : this we could either add more special blitters here, or detect antialiasing in the
150 : paint and return null if it is set, forcing the client to take the slow shader case
151 : (which does respect soft edges).
152 : */
153 118 : SkASSERT(allocator != nullptr);
154 :
155 : // Defer to the general code if the pixels are unpremultipled. This case is not common,
156 : // and this simplifies the code.
157 118 : if (source.alphaType() == kUnpremul_SkAlphaType) {
158 0 : return nullptr;
159 : }
160 :
161 118 : SkSpriteBlitter* blitter = nullptr;
162 :
163 118 : if (SkSpriteBlitter_Src_SrcOver::Supports(dst, source, paint)) {
164 17 : blitter = allocator->make<SkSpriteBlitter_Src_SrcOver>(source);
165 : } else {
166 101 : switch (dst.colorType()) {
167 : case kRGB_565_SkColorType:
168 0 : blitter = SkSpriteBlitter::ChooseD16(source, paint, allocator);
169 0 : break;
170 : case kN32_SkColorType:
171 101 : if (dst.info().gammaCloseToSRGB()) {
172 0 : blitter = SkSpriteBlitter::ChooseS32(source, paint, allocator);
173 : } else {
174 101 : blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator);
175 : }
176 101 : break;
177 : case kRGBA_F16_SkColorType:
178 0 : blitter = SkSpriteBlitter::ChooseF16(source, paint, allocator);
179 0 : break;
180 : default:
181 0 : break;
182 : }
183 : }
184 :
185 118 : if (blitter) {
186 118 : blitter->setup(dst, left, top, paint);
187 : }
188 118 : return blitter;
189 : }
|