blob: ff7d4660664c91c9a1fae83d5a555853c0ccadca [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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
Herb Derby57bfa022017-02-09 17:25:43 -05008#include "SkArenaAlloc.h"
Mike Klein5cc9da62017-05-31 14:18:07 -04009#include "SkColorSpace.h"
10#include "SkCoreBlitters.h"
herba62038c2016-05-26 10:56:17 -070011#include "SkOpts.h"
Mike Klein5cc9da62017-05-31 14:18:07 -040012#include "SkPM4fPriv.h"
13#include "SkRasterPipeline.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkSpriteBlitter.h"
15
herb7df9e4a2016-06-10 13:01:27 -070016SkSpriteBlitter::SkSpriteBlitter(const SkPixmap& source)
17 : fSource(source) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000018
reedcb674142015-06-05 06:58:22 -070019void SkSpriteBlitter::setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) {
20 fDst = dst;
reed@android.com8a1c16f2008-12-17 15:59:43 +000021 fLeft = left;
22 fTop = top;
23 fPaint = &paint;
24}
25
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +000026void SkSpriteBlitter::blitH(int x, int y, int width) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000027 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070028
29 // Fallback to blitRect.
30 this->blitRect(x, y, width, 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +000031}
32
herb7df9e4a2016-06-10 13:01:27 -070033void SkSpriteBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000034 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070035
36 // No fallback strategy.
reed@android.com8a1c16f2008-12-17 15:59:43 +000037}
38
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +000039void SkSpriteBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000040 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070041
42 // Fall back to superclass if the code gets here in release mode.
43 INHERITED::blitV(x, y, height, alpha);
reed@android.com8a1c16f2008-12-17 15:59:43 +000044}
45
herb7df9e4a2016-06-10 13:01:27 -070046void SkSpriteBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000047 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070048
49 // Fall back to superclass if the code gets here in release mode.
50 INHERITED::blitMask(mask, clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +000051}
reed@android.com8a1c16f2008-12-17 15:59:43 +000052
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +000053///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000054
Mike Reed1919dc42017-05-31 09:25:18 -040055class SkSpriteBlitter_Memcpy final : public SkSpriteBlitter {
reed8c3fd4f2016-04-15 06:59:38 -070056public:
57 static bool Supports(const SkPixmap& dst, const SkPixmap& src, const SkPaint& paint) {
58 if (dst.colorType() != src.colorType()) {
59 return false;
60 }
Mike Klein23980332017-05-31 12:13:42 -040061 if (!SkColorSpace::Equals(dst.colorSpace(), src.colorSpace())) {
62 return false;
63 }
reed8c3fd4f2016-04-15 06:59:38 -070064 if (paint.getMaskFilter() || paint.getColorFilter() || paint.getImageFilter()) {
65 return false;
66 }
67 if (0xFF != paint.getAlpha()) {
68 return false;
69 }
reed374772b2016-10-05 17:33:02 -070070 SkBlendMode mode = paint.getBlendMode();
Mike Reed1919dc42017-05-31 09:25:18 -040071 return SkBlendMode::kSrc == mode || (SkBlendMode::kSrcOver == mode && src.isOpaque());
reed8c3fd4f2016-04-15 06:59:38 -070072 }
73
Mike Reed1919dc42017-05-31 09:25:18 -040074 SkSpriteBlitter_Memcpy(const SkPixmap& src)
herb7df9e4a2016-06-10 13:01:27 -070075 : INHERITED(src) {}
reed8c3fd4f2016-04-15 06:59:38 -070076
reed8c3fd4f2016-04-15 06:59:38 -070077 void blitRect(int x, int y, int width, int height) override {
78 SkASSERT(fDst.colorType() == fSource.colorType());
reed8c3fd4f2016-04-15 06:59:38 -070079 SkASSERT(width > 0 && height > 0);
80
Mike Reed1919dc42017-05-31 09:25:18 -040081 char* dst = (char*)fDst.writable_addr(x, y);
82 const char* src = (const char*)fSource.addr(x - fLeft, y - fTop);
83 const size_t dstRB = fDst.rowBytes();
84 const size_t srcRB = fSource.rowBytes();
85 const size_t bytesToCopy = width << fSource.shiftPerPixel();
reed8c3fd4f2016-04-15 06:59:38 -070086
Mike Reed1919dc42017-05-31 09:25:18 -040087 while (height --> 0) {
88 memcpy(dst, src, bytesToCopy);
89 dst += dstRB;
90 src += srcRB;
reed8c3fd4f2016-04-15 06:59:38 -070091 }
92 }
93
herba62038c2016-05-26 10:56:17 -070094private:
reed8c3fd4f2016-04-15 06:59:38 -070095 typedef SkSpriteBlitter INHERITED;
herba62038c2016-05-26 10:56:17 -070096};
reed8c3fd4f2016-04-15 06:59:38 -070097
Mike Klein5cc9da62017-05-31 14:18:07 -040098class SkRasterPipelineSpriteBlitter : public SkSpriteBlitter {
99public:
100 SkRasterPipelineSpriteBlitter(const SkPixmap& src, SkArenaAlloc* alloc)
101 : INHERITED(src)
102 , fAlloc(alloc)
103 , fBlitter(nullptr)
104 , fSrcPtr(nullptr)
105 {}
106
107 static bool Supports(const SkPixmap& src) {
Mike Reed58050132017-07-12 22:10:29 -0400108#ifdef SK_SUPPORT_LEGACY_INDEX_8_COLORTYPE
Mike Klein5cc9da62017-05-31 14:18:07 -0400109 // We'd need to add a load_i8 stage.
110 return src.colorType() != kIndex_8_SkColorType;
Mike Reed58050132017-07-12 22:10:29 -0400111#else
112 return true;
113#endif
Mike Klein5cc9da62017-05-31 14:18:07 -0400114 }
115
116 void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override {
117 fDst = dst;
118 fLeft = left;
119 fTop = top;
120
121 fPaintColor = SkColor4f_from_SkColor(paint.getColor(), fDst.colorSpace());
122
123 SkRasterPipeline p(fAlloc);
124 switch (fSource.colorType()) {
125 case kAlpha_8_SkColorType: p.append(SkRasterPipeline::load_a8, &fSrcPtr); break;
126 case kGray_8_SkColorType: p.append(SkRasterPipeline::load_g8, &fSrcPtr); break;
127 case kRGB_565_SkColorType: p.append(SkRasterPipeline::load_565, &fSrcPtr); break;
128 case kARGB_4444_SkColorType: p.append(SkRasterPipeline::load_4444, &fSrcPtr); break;
Mike Kleinc2d20762017-06-27 19:53:21 -0400129 case kBGRA_8888_SkColorType: p.append(SkRasterPipeline::load_bgra, &fSrcPtr); break;
130 case kRGBA_8888_SkColorType: p.append(SkRasterPipeline::load_8888, &fSrcPtr); break;
Mike Klein5cc9da62017-05-31 14:18:07 -0400131 case kRGBA_F16_SkColorType: p.append(SkRasterPipeline::load_f16, &fSrcPtr); break;
132 default: SkASSERT(false);
133 }
134 if (fDst.colorSpace() &&
135 (!fSource.colorSpace() || fSource.colorSpace()->gammaCloseToSRGB())) {
136 p.append_from_srgb(fSource.alphaType());
137 }
Mike Klein5cc9da62017-05-31 14:18:07 -0400138 if (fSource.colorType() == kAlpha_8_SkColorType) {
139 p.append(SkRasterPipeline::set_rgb, &fPaintColor);
140 p.append(SkRasterPipeline::premul);
141 }
142 append_gamut_transform(&p, fAlloc,
143 fSource.colorSpace(), fDst.colorSpace(), kPremul_SkAlphaType);
144 if (fPaintColor.fA != 1.0f) {
145 p.append(SkRasterPipeline::scale_1_float, &fPaintColor.fA);
146 }
147
Mike Reedeb7dc792017-06-12 12:48:45 -0400148 bool is_opaque = fSource.isOpaque() && fPaintColor.fA == 1.0f;
149 fBlitter = SkCreateRasterPipelineBlitter(fDst, paint, p, is_opaque, fAlloc);
Mike Klein5cc9da62017-05-31 14:18:07 -0400150 }
151
152 void blitRect(int x, int y, int width, int height) override {
153 fSrcPtr = (const char*)fSource.addr(x-fLeft,y-fTop);
154
155 // Our pipeline will load from fSrcPtr+x, fSrcPtr+x+1, etc.,
156 // so we back up an extra x pixels to start at 0.
157 fSrcPtr -= fSource.info().bytesPerPixel() * x;
158
159 while (height --> 0) {
160 fBlitter->blitH(x,y++, width);
161 fSrcPtr += fSource.rowBytes();
162 }
163 }
164
165private:
166 SkArenaAlloc* fAlloc;
167 SkBlitter* fBlitter;
168 const char* fSrcPtr;
169 SkColor4f fPaintColor;
170
171 typedef SkSpriteBlitter INHERITED;
172};
173
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174// returning null means the caller will call SkBlitter::Choose() and
175// have wrapped the source bitmap inside a shader
reedcb674142015-06-05 06:58:22 -0700176SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint,
Herb Derby57bfa022017-02-09 17:25:43 -0500177 const SkPixmap& source, int left, int top, SkArenaAlloc* allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 /* We currently ignore antialiasing and filtertype, meaning we will take our
179 special blitters regardless of these settings. Ignoring filtertype seems fine
180 since by definition there is no scale in the matrix. Ignoring antialiasing is
181 a bit of a hack, since we "could" pass in the fractional left/top for the bitmap,
182 and respect that by blending the edges of the bitmap against the device. To support
183 this we could either add more special blitters here, or detect antialiasing in the
184 paint and return null if it is set, forcing the client to take the slow shader case
185 (which does respect soft edges).
186 */
halcanary96fcdcc2015-08-27 07:41:13 -0700187 SkASSERT(allocator != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188
herb58238462016-06-03 09:44:53 -0700189 if (source.alphaType() == kUnpremul_SkAlphaType) {
190 return nullptr;
191 }
192
herba62038c2016-05-26 10:56:17 -0700193 SkSpriteBlitter* blitter = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194
Mike Klein5cc9da62017-05-31 14:18:07 -0400195 if (!blitter && SkSpriteBlitter_Memcpy::Supports(dst, source, paint)) {
Mike Reed1919dc42017-05-31 09:25:18 -0400196 blitter = allocator->make<SkSpriteBlitter_Memcpy>(source);
Mike Klein5cc9da62017-05-31 14:18:07 -0400197 }
198 if (!blitter && !dst.colorSpace() && dst.colorType() == kN32_SkColorType) {
199 blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator);
200 }
201 if (!blitter && SkRasterPipelineSpriteBlitter::Supports(source)) {
202 blitter = allocator->make<SkRasterPipelineSpriteBlitter>(source, allocator);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203 }
204
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000205 if (blitter) {
reedcb674142015-06-05 06:58:22 -0700206 blitter->setup(dst, left, top, paint);
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000207 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208 return blitter;
209}