blob: 9f34391bc0afc9c5311ff9838620475e40b23fd1 [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
Mike Klein5cc9da62017-05-31 14:18:07 -0400107 void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override {
108 fDst = dst;
109 fLeft = left;
110 fTop = top;
111
112 fPaintColor = SkColor4f_from_SkColor(paint.getColor(), fDst.colorSpace());
113
114 SkRasterPipeline p(fAlloc);
115 switch (fSource.colorType()) {
116 case kAlpha_8_SkColorType: p.append(SkRasterPipeline::load_a8, &fSrcPtr); break;
117 case kGray_8_SkColorType: p.append(SkRasterPipeline::load_g8, &fSrcPtr); break;
118 case kRGB_565_SkColorType: p.append(SkRasterPipeline::load_565, &fSrcPtr); break;
119 case kARGB_4444_SkColorType: p.append(SkRasterPipeline::load_4444, &fSrcPtr); break;
Mike Kleinc2d20762017-06-27 19:53:21 -0400120 case kBGRA_8888_SkColorType: p.append(SkRasterPipeline::load_bgra, &fSrcPtr); break;
121 case kRGBA_8888_SkColorType: p.append(SkRasterPipeline::load_8888, &fSrcPtr); break;
Mike Klein5cc9da62017-05-31 14:18:07 -0400122 case kRGBA_F16_SkColorType: p.append(SkRasterPipeline::load_f16, &fSrcPtr); break;
123 default: SkASSERT(false);
124 }
125 if (fDst.colorSpace() &&
126 (!fSource.colorSpace() || fSource.colorSpace()->gammaCloseToSRGB())) {
127 p.append_from_srgb(fSource.alphaType());
128 }
Mike Klein5cc9da62017-05-31 14:18:07 -0400129 if (fSource.colorType() == kAlpha_8_SkColorType) {
130 p.append(SkRasterPipeline::set_rgb, &fPaintColor);
131 p.append(SkRasterPipeline::premul);
132 }
133 append_gamut_transform(&p, fAlloc,
134 fSource.colorSpace(), fDst.colorSpace(), kPremul_SkAlphaType);
135 if (fPaintColor.fA != 1.0f) {
136 p.append(SkRasterPipeline::scale_1_float, &fPaintColor.fA);
137 }
138
Mike Reedeb7dc792017-06-12 12:48:45 -0400139 bool is_opaque = fSource.isOpaque() && fPaintColor.fA == 1.0f;
140 fBlitter = SkCreateRasterPipelineBlitter(fDst, paint, p, is_opaque, fAlloc);
Mike Klein5cc9da62017-05-31 14:18:07 -0400141 }
142
143 void blitRect(int x, int y, int width, int height) override {
144 fSrcPtr = (const char*)fSource.addr(x-fLeft,y-fTop);
145
146 // Our pipeline will load from fSrcPtr+x, fSrcPtr+x+1, etc.,
147 // so we back up an extra x pixels to start at 0.
148 fSrcPtr -= fSource.info().bytesPerPixel() * x;
149
150 while (height --> 0) {
151 fBlitter->blitH(x,y++, width);
152 fSrcPtr += fSource.rowBytes();
153 }
154 }
155
156private:
157 SkArenaAlloc* fAlloc;
158 SkBlitter* fBlitter;
159 const char* fSrcPtr;
160 SkColor4f fPaintColor;
161
162 typedef SkSpriteBlitter INHERITED;
163};
164
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165// returning null means the caller will call SkBlitter::Choose() and
166// have wrapped the source bitmap inside a shader
reedcb674142015-06-05 06:58:22 -0700167SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint,
Herb Derby57bfa022017-02-09 17:25:43 -0500168 const SkPixmap& source, int left, int top, SkArenaAlloc* allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169 /* We currently ignore antialiasing and filtertype, meaning we will take our
170 special blitters regardless of these settings. Ignoring filtertype seems fine
171 since by definition there is no scale in the matrix. Ignoring antialiasing is
172 a bit of a hack, since we "could" pass in the fractional left/top for the bitmap,
173 and respect that by blending the edges of the bitmap against the device. To support
174 this we could either add more special blitters here, or detect antialiasing in the
175 paint and return null if it is set, forcing the client to take the slow shader case
176 (which does respect soft edges).
177 */
halcanary96fcdcc2015-08-27 07:41:13 -0700178 SkASSERT(allocator != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179
herb58238462016-06-03 09:44:53 -0700180 if (source.alphaType() == kUnpremul_SkAlphaType) {
181 return nullptr;
182 }
183
herba62038c2016-05-26 10:56:17 -0700184 SkSpriteBlitter* blitter = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185
Mike Klein5cc9da62017-05-31 14:18:07 -0400186 if (!blitter && SkSpriteBlitter_Memcpy::Supports(dst, source, paint)) {
Mike Reed1919dc42017-05-31 09:25:18 -0400187 blitter = allocator->make<SkSpriteBlitter_Memcpy>(source);
Mike Klein5cc9da62017-05-31 14:18:07 -0400188 }
189 if (!blitter && !dst.colorSpace() && dst.colorType() == kN32_SkColorType) {
190 blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator);
191 }
Mike Reed262b3192017-07-17 10:13:58 -0400192 if (!blitter) {
Mike Klein5cc9da62017-05-31 14:18:07 -0400193 blitter = allocator->make<SkRasterPipelineSpriteBlitter>(source, allocator);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194 }
195
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000196 if (blitter) {
reedcb674142015-06-05 06:58:22 -0700197 blitter->setup(dst, left, top, paint);
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000198 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199 return blitter;
200}