blob: 73851281950b8a1393e4ea6ee90924674170270c [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"
Mike Klein45c16fa2017-07-18 18:15:13 -040015#include "../jumper/SkJumper.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016
herb7df9e4a2016-06-10 13:01:27 -070017SkSpriteBlitter::SkSpriteBlitter(const SkPixmap& source)
18 : fSource(source) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000019
reedcb674142015-06-05 06:58:22 -070020void SkSpriteBlitter::setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) {
21 fDst = dst;
reed@android.com8a1c16f2008-12-17 15:59:43 +000022 fLeft = left;
23 fTop = top;
24 fPaint = &paint;
25}
26
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +000027void SkSpriteBlitter::blitH(int x, int y, int width) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000028 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070029
30 // Fallback to blitRect.
31 this->blitRect(x, y, width, 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +000032}
33
herb7df9e4a2016-06-10 13:01:27 -070034void SkSpriteBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000035 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070036
37 // No fallback strategy.
reed@android.com8a1c16f2008-12-17 15:59:43 +000038}
39
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +000040void SkSpriteBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000041 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070042
43 // Fall back to superclass if the code gets here in release mode.
44 INHERITED::blitV(x, y, height, alpha);
reed@android.com8a1c16f2008-12-17 15:59:43 +000045}
46
herb7df9e4a2016-06-10 13:01:27 -070047void SkSpriteBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000048 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070049
50 // Fall back to superclass if the code gets here in release mode.
51 INHERITED::blitMask(mask, clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +000052}
reed@android.com8a1c16f2008-12-17 15:59:43 +000053
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +000054///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000055
Mike Reed1919dc42017-05-31 09:25:18 -040056class SkSpriteBlitter_Memcpy final : public SkSpriteBlitter {
reed8c3fd4f2016-04-15 06:59:38 -070057public:
58 static bool Supports(const SkPixmap& dst, const SkPixmap& src, const SkPaint& paint) {
59 if (dst.colorType() != src.colorType()) {
60 return false;
61 }
Mike Klein23980332017-05-31 12:13:42 -040062 if (!SkColorSpace::Equals(dst.colorSpace(), src.colorSpace())) {
63 return false;
64 }
reed8c3fd4f2016-04-15 06:59:38 -070065 if (paint.getMaskFilter() || paint.getColorFilter() || paint.getImageFilter()) {
66 return false;
67 }
68 if (0xFF != paint.getAlpha()) {
69 return false;
70 }
reed374772b2016-10-05 17:33:02 -070071 SkBlendMode mode = paint.getBlendMode();
Mike Reed1919dc42017-05-31 09:25:18 -040072 return SkBlendMode::kSrc == mode || (SkBlendMode::kSrcOver == mode && src.isOpaque());
reed8c3fd4f2016-04-15 06:59:38 -070073 }
74
Mike Reed1919dc42017-05-31 09:25:18 -040075 SkSpriteBlitter_Memcpy(const SkPixmap& src)
herb7df9e4a2016-06-10 13:01:27 -070076 : INHERITED(src) {}
reed8c3fd4f2016-04-15 06:59:38 -070077
reed8c3fd4f2016-04-15 06:59:38 -070078 void blitRect(int x, int y, int width, int height) override {
79 SkASSERT(fDst.colorType() == fSource.colorType());
reed8c3fd4f2016-04-15 06:59:38 -070080 SkASSERT(width > 0 && height > 0);
81
Mike Reed1919dc42017-05-31 09:25:18 -040082 char* dst = (char*)fDst.writable_addr(x, y);
83 const char* src = (const char*)fSource.addr(x - fLeft, y - fTop);
84 const size_t dstRB = fDst.rowBytes();
85 const size_t srcRB = fSource.rowBytes();
86 const size_t bytesToCopy = width << fSource.shiftPerPixel();
reed8c3fd4f2016-04-15 06:59:38 -070087
Mike Reed1919dc42017-05-31 09:25:18 -040088 while (height --> 0) {
89 memcpy(dst, src, bytesToCopy);
90 dst += dstRB;
91 src += srcRB;
reed8c3fd4f2016-04-15 06:59:38 -070092 }
93 }
94
herba62038c2016-05-26 10:56:17 -070095private:
reed8c3fd4f2016-04-15 06:59:38 -070096 typedef SkSpriteBlitter INHERITED;
herba62038c2016-05-26 10:56:17 -070097};
reed8c3fd4f2016-04-15 06:59:38 -070098
Mike Klein5cc9da62017-05-31 14:18:07 -040099class SkRasterPipelineSpriteBlitter : public SkSpriteBlitter {
100public:
101 SkRasterPipelineSpriteBlitter(const SkPixmap& src, SkArenaAlloc* alloc)
102 : INHERITED(src)
103 , fAlloc(alloc)
104 , fBlitter(nullptr)
Mike Klein45c16fa2017-07-18 18:15:13 -0400105 , fSrcPtr{nullptr, 0}
Mike Klein5cc9da62017-05-31 14:18:07 -0400106 {}
107
Mike Klein5cc9da62017-05-31 14:18:07 -0400108 void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override {
109 fDst = dst;
110 fLeft = left;
111 fTop = top;
112
113 fPaintColor = SkColor4f_from_SkColor(paint.getColor(), fDst.colorSpace());
114
115 SkRasterPipeline p(fAlloc);
Mike Kleinac568a92018-01-25 09:09:32 -0500116 void* ctx = &fSrcPtr;
Mike Klein5cc9da62017-05-31 14:18:07 -0400117 switch (fSource.colorType()) {
Mike Kleinac568a92018-01-25 09:09:32 -0500118 case kAlpha_8_SkColorType: p.append(SkRasterPipeline::load_a8, ctx); break;
119 case kGray_8_SkColorType: p.append(SkRasterPipeline::load_g8, ctx); break;
120 case kRGB_565_SkColorType: p.append(SkRasterPipeline::load_565, ctx); break;
121 case kARGB_4444_SkColorType: p.append(SkRasterPipeline::load_4444, ctx); break;
122 case kBGRA_8888_SkColorType: p.append(SkRasterPipeline::load_bgra, ctx); break;
123 case kRGBA_8888_SkColorType: p.append(SkRasterPipeline::load_8888, ctx); break;
124 case kRGBA_1010102_SkColorType: p.append(SkRasterPipeline::load_1010102, ctx); break;
125 case kRGBA_F16_SkColorType: p.append(SkRasterPipeline::load_f16, ctx); break;
126
127 case kRGB_888x_SkColorType: p.append(SkRasterPipeline::load_8888, ctx);
128 p.append(SkRasterPipeline::force_opaque ); break;
129 case kRGB_101010x_SkColorType: p.append(SkRasterPipeline::load_1010102, ctx);
130 p.append(SkRasterPipeline::force_opaque ); break;
Mike Klein5cc9da62017-05-31 14:18:07 -0400131 default: SkASSERT(false);
132 }
133 if (fDst.colorSpace() &&
134 (!fSource.colorSpace() || fSource.colorSpace()->gammaCloseToSRGB())) {
Mike Kleinf1f11622017-12-18 14:07:31 -0500135 p.append(SkRasterPipeline::from_srgb);
Mike Klein5cc9da62017-05-31 14:18:07 -0400136 }
Mike Klein5cc9da62017-05-31 14:18:07 -0400137 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 {
Mike Klein45c16fa2017-07-18 18:15:13 -0400152 fSrcPtr.stride = fSource.rowBytesAsPixels();
Mike Klein548d3872018-01-24 15:36:35 -0500153
154 // We really want fSrcPtr.pixels = fSource.addr(-fLeft, -fTop) here, but that asserts.
155 // Instead we ask for addr(-fLeft+x, -fTop+y), then back up (x,y) manually.
156 // Representing bpp as a size_t keeps all this math in size_t instead of int,
157 // which could wrap around with large enough fSrcPtr.stride and y.
158 size_t bpp = fSource.info().bytesPerPixel();
159 fSrcPtr.pixels = (char*)fSource.addr(-fLeft+x, -fTop+y) - bpp * x
160 - bpp * y * fSrcPtr.stride;
Mike Klein5cc9da62017-05-31 14:18:07 -0400161
Mike Klein45c16fa2017-07-18 18:15:13 -0400162 fBlitter->blitRect(x,y,width,height);
Mike Klein5cc9da62017-05-31 14:18:07 -0400163 }
164
165private:
Mike Klein45c16fa2017-07-18 18:15:13 -0400166 SkArenaAlloc* fAlloc;
167 SkBlitter* fBlitter;
168 SkJumper_MemoryCtx fSrcPtr;
169 SkColor4f fPaintColor;
Mike Klein5cc9da62017-05-31 14:18:07 -0400170
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 }
Mike Reedef8ce282017-10-05 16:04:41 -0400198 if (!blitter && !dst.colorSpace()) {
199 switch (dst.colorType()) {
200 case kN32_SkColorType:
201 blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator);
202 break;
203 case kRGB_565_SkColorType:
204 blitter = SkSpriteBlitter::ChooseL565(source, paint, allocator);
205 break;
206 case kAlpha_8_SkColorType:
207 blitter = SkSpriteBlitter::ChooseLA8(source, paint, allocator);
208 break;
209 default:
210 break;
211 }
Mike Klein5cc9da62017-05-31 14:18:07 -0400212 }
Mike Reed28266272018-01-17 23:04:04 -0500213 if (!blitter && !paint.getMaskFilter()) {
Mike Klein5cc9da62017-05-31 14:18:07 -0400214 blitter = allocator->make<SkRasterPipelineSpriteBlitter>(source, allocator);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215 }
216
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000217 if (blitter) {
reedcb674142015-06-05 06:58:22 -0700218 blitter->setup(dst, left, top, paint);
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000219 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220 return blitter;
221}