blob: 20ec357a7b43c3e03b662abdff8f6863d60bb62e [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;
125 case kRGBA_8888_SkColorType:
126 case kBGRA_8888_SkColorType: p.append(SkRasterPipeline::load_8888, &fSrcPtr); break;
127 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 }
134 if (fSource.colorType() == kBGRA_8888_SkColorType) {
135 p.append(SkRasterPipeline::swap_rb);
136 }
137 if (fSource.colorType() == kAlpha_8_SkColorType) {
138 p.append(SkRasterPipeline::set_rgb, &fPaintColor);
139 p.append(SkRasterPipeline::premul);
140 }
141 append_gamut_transform(&p, fAlloc,
142 fSource.colorSpace(), fDst.colorSpace(), kPremul_SkAlphaType);
143 if (fPaintColor.fA != 1.0f) {
144 p.append(SkRasterPipeline::scale_1_float, &fPaintColor.fA);
145 }
146
Mike Reedeb7dc792017-06-12 12:48:45 -0400147 bool is_opaque = fSource.isOpaque() && fPaintColor.fA == 1.0f;
148 fBlitter = SkCreateRasterPipelineBlitter(fDst, paint, p, is_opaque, fAlloc);
Mike Klein5cc9da62017-05-31 14:18:07 -0400149 }
150
151 void blitRect(int x, int y, int width, int height) override {
152 fSrcPtr = (const char*)fSource.addr(x-fLeft,y-fTop);
153
154 // Our pipeline will load from fSrcPtr+x, fSrcPtr+x+1, etc.,
155 // so we back up an extra x pixels to start at 0.
156 fSrcPtr -= fSource.info().bytesPerPixel() * x;
157
158 while (height --> 0) {
159 fBlitter->blitH(x,y++, width);
160 fSrcPtr += fSource.rowBytes();
161 }
162 }
163
164private:
165 SkArenaAlloc* fAlloc;
166 SkBlitter* fBlitter;
167 const char* fSrcPtr;
168 SkColor4f fPaintColor;
169
170 typedef SkSpriteBlitter INHERITED;
171};
172
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173// returning null means the caller will call SkBlitter::Choose() and
174// have wrapped the source bitmap inside a shader
reedcb674142015-06-05 06:58:22 -0700175SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint,
Herb Derby57bfa022017-02-09 17:25:43 -0500176 const SkPixmap& source, int left, int top, SkArenaAlloc* allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 /* We currently ignore antialiasing and filtertype, meaning we will take our
178 special blitters regardless of these settings. Ignoring filtertype seems fine
179 since by definition there is no scale in the matrix. Ignoring antialiasing is
180 a bit of a hack, since we "could" pass in the fractional left/top for the bitmap,
181 and respect that by blending the edges of the bitmap against the device. To support
182 this we could either add more special blitters here, or detect antialiasing in the
183 paint and return null if it is set, forcing the client to take the slow shader case
184 (which does respect soft edges).
185 */
halcanary96fcdcc2015-08-27 07:41:13 -0700186 SkASSERT(allocator != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187
herb58238462016-06-03 09:44:53 -0700188 if (source.alphaType() == kUnpremul_SkAlphaType) {
189 return nullptr;
190 }
Mike Reed428266d2017-06-24 18:17:49 -0400191#ifndef SK_SUPPORT_LEGACY_COLORFILTER_FILTERSPAN
192 if (paint.getColorFilter()) {
193 return nullptr;
194 }
195#endif
herb58238462016-06-03 09:44:53 -0700196
herba62038c2016-05-26 10:56:17 -0700197 SkSpriteBlitter* blitter = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198
Mike Klein5cc9da62017-05-31 14:18:07 -0400199 if (!blitter && SkSpriteBlitter_Memcpy::Supports(dst, source, paint)) {
Mike Reed1919dc42017-05-31 09:25:18 -0400200 blitter = allocator->make<SkSpriteBlitter_Memcpy>(source);
Mike Klein5cc9da62017-05-31 14:18:07 -0400201 }
202 if (!blitter && !dst.colorSpace() && dst.colorType() == kN32_SkColorType) {
203 blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator);
204 }
205 if (!blitter && SkRasterPipelineSpriteBlitter::Supports(source)) {
206 blitter = allocator->make<SkRasterPipelineSpriteBlitter>(source, allocator);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207 }
208
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000209 if (blitter) {
reedcb674142015-06-05 06:58:22 -0700210 blitter->setup(dst, left, top, paint);
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000211 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 return blitter;
213}