blob: 9b1ee2946e021c3ace2d25cad02d179744a48e6e [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) {
108 // We'd need to add a load_i8 stage.
109 return src.colorType() != kIndex_8_SkColorType;
110 }
111
112 void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override {
113 fDst = dst;
114 fLeft = left;
115 fTop = top;
116
117 fPaintColor = SkColor4f_from_SkColor(paint.getColor(), fDst.colorSpace());
118
119 SkRasterPipeline p(fAlloc);
120 switch (fSource.colorType()) {
121 case kAlpha_8_SkColorType: p.append(SkRasterPipeline::load_a8, &fSrcPtr); break;
122 case kGray_8_SkColorType: p.append(SkRasterPipeline::load_g8, &fSrcPtr); break;
123 case kRGB_565_SkColorType: p.append(SkRasterPipeline::load_565, &fSrcPtr); break;
124 case kARGB_4444_SkColorType: p.append(SkRasterPipeline::load_4444, &fSrcPtr); break;
Mike Kleinc2d20762017-06-27 19:53:21 -0400125 case kBGRA_8888_SkColorType: p.append(SkRasterPipeline::load_bgra, &fSrcPtr); break;
126 case kRGBA_8888_SkColorType: p.append(SkRasterPipeline::load_8888, &fSrcPtr); break;
Mike Klein5cc9da62017-05-31 14:18:07 -0400127 case kRGBA_F16_SkColorType: p.append(SkRasterPipeline::load_f16, &fSrcPtr); break;
128 default: SkASSERT(false);
129 }
130 if (fDst.colorSpace() &&
131 (!fSource.colorSpace() || fSource.colorSpace()->gammaCloseToSRGB())) {
132 p.append_from_srgb(fSource.alphaType());
133 }
Mike Klein5cc9da62017-05-31 14:18:07 -0400134 if (fSource.colorType() == kAlpha_8_SkColorType) {
135 p.append(SkRasterPipeline::set_rgb, &fPaintColor);
136 p.append(SkRasterPipeline::premul);
137 }
138 append_gamut_transform(&p, fAlloc,
139 fSource.colorSpace(), fDst.colorSpace(), kPremul_SkAlphaType);
140 if (fPaintColor.fA != 1.0f) {
141 p.append(SkRasterPipeline::scale_1_float, &fPaintColor.fA);
142 }
143
Mike Reedeb7dc792017-06-12 12:48:45 -0400144 bool is_opaque = fSource.isOpaque() && fPaintColor.fA == 1.0f;
145 fBlitter = SkCreateRasterPipelineBlitter(fDst, paint, p, is_opaque, fAlloc);
Mike Klein5cc9da62017-05-31 14:18:07 -0400146 }
147
148 void blitRect(int x, int y, int width, int height) override {
149 fSrcPtr = (const char*)fSource.addr(x-fLeft,y-fTop);
150
151 // Our pipeline will load from fSrcPtr+x, fSrcPtr+x+1, etc.,
152 // so we back up an extra x pixels to start at 0.
153 fSrcPtr -= fSource.info().bytesPerPixel() * x;
154
155 while (height --> 0) {
156 fBlitter->blitH(x,y++, width);
157 fSrcPtr += fSource.rowBytes();
158 }
159 }
160
161private:
162 SkArenaAlloc* fAlloc;
163 SkBlitter* fBlitter;
164 const char* fSrcPtr;
165 SkColor4f fPaintColor;
166
167 typedef SkSpriteBlitter INHERITED;
168};
169
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170// returning null means the caller will call SkBlitter::Choose() and
171// have wrapped the source bitmap inside a shader
reedcb674142015-06-05 06:58:22 -0700172SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint,
Herb Derby57bfa022017-02-09 17:25:43 -0500173 const SkPixmap& source, int left, int top, SkArenaAlloc* allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174 /* We currently ignore antialiasing and filtertype, meaning we will take our
175 special blitters regardless of these settings. Ignoring filtertype seems fine
176 since by definition there is no scale in the matrix. Ignoring antialiasing is
177 a bit of a hack, since we "could" pass in the fractional left/top for the bitmap,
178 and respect that by blending the edges of the bitmap against the device. To support
179 this we could either add more special blitters here, or detect antialiasing in the
180 paint and return null if it is set, forcing the client to take the slow shader case
181 (which does respect soft edges).
182 */
halcanary96fcdcc2015-08-27 07:41:13 -0700183 SkASSERT(allocator != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184
herb58238462016-06-03 09:44:53 -0700185 if (source.alphaType() == kUnpremul_SkAlphaType) {
186 return nullptr;
187 }
Mike Reed428266d2017-06-24 18:17:49 -0400188#ifndef SK_SUPPORT_LEGACY_COLORFILTER_FILTERSPAN
189 if (paint.getColorFilter()) {
190 return nullptr;
191 }
192#endif
herb58238462016-06-03 09:44:53 -0700193
herba62038c2016-05-26 10:56:17 -0700194 SkSpriteBlitter* blitter = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195
Mike Klein5cc9da62017-05-31 14:18:07 -0400196 if (!blitter && SkSpriteBlitter_Memcpy::Supports(dst, source, paint)) {
Mike Reed1919dc42017-05-31 09:25:18 -0400197 blitter = allocator->make<SkSpriteBlitter_Memcpy>(source);
Mike Klein5cc9da62017-05-31 14:18:07 -0400198 }
199 if (!blitter && !dst.colorSpace() && dst.colorType() == kN32_SkColorType) {
200 blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator);
201 }
202 if (!blitter && SkRasterPipelineSpriteBlitter::Supports(source)) {
203 blitter = allocator->make<SkRasterPipelineSpriteBlitter>(source, allocator);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204 }
205
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000206 if (blitter) {
reedcb674142015-06-05 06:58:22 -0700207 blitter->setup(dst, left, top, paint);
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000208 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209 return blitter;
210}