blob: ca317786ada800a39a9c21cbfdac82f6617b31f6 [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"
Mike Kleine28a6b52018-07-25 13:05:17 -040010#include "SkColorSpacePriv.h"
Mike Kleinfcc10da2018-07-11 14:30:27 -040011#include "SkColorSpaceXformSteps.h"
Mike Klein5cc9da62017-05-31 14:18:07 -040012#include "SkCoreBlitters.h"
herba62038c2016-05-26 10:56:17 -070013#include "SkOpts.h"
Mike Klein5cc9da62017-05-31 14:18:07 -040014#include "SkRasterPipeline.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkSpriteBlitter.h"
16
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;
Mike Kleinbe569492018-09-14 09:34:21 -0400112 fPaintColor = paint.getColor4f();
Mike Klein5cc9da62017-05-31 14:18:07 -0400113
114 SkRasterPipeline p(fAlloc);
Mike Kleinafa35022018-09-17 16:41:26 -0400115 p.append_load(fSource.colorType(), &fSrcPtr);
Mike Klein9fb5a532018-09-13 15:23:38 -0400116
Mike Klein5cc9da62017-05-31 14:18:07 -0400117 if (fSource.colorType() == kAlpha_8_SkColorType) {
Mike Kleinfcc10da2018-07-11 14:30:27 -0400118 // The color for A8 images comes from the (sRGB) paint color.
Mike Kleinbe569492018-09-14 09:34:21 -0400119 p.append_set_rgb(fAlloc, fPaintColor);
Mike Klein5cc9da62017-05-31 14:18:07 -0400120 p.append(SkRasterPipeline::premul);
121 }
Mike Kleinfcc10da2018-07-11 14:30:27 -0400122 if (auto dstCS = fDst.colorSpace()) {
123 auto srcCS = fSource.colorSpace();
124 if (!srcCS || fSource.colorType() == kAlpha_8_SkColorType) {
125 // We treat untagged images as sRGB.
126 // A8 images get their r,g,b from the paint color, so they're also sRGB.
Mike Kleine28a6b52018-07-25 13:05:17 -0400127 srcCS = sk_srgb_singleton();
Mike Kleinfcc10da2018-07-11 14:30:27 -0400128 }
Mike Kleine28c7912018-08-14 11:49:34 -0400129 auto srcAT = fSource.isOpaque() ? kOpaque_SkAlphaType
130 : kPremul_SkAlphaType;
131 fAlloc->make<SkColorSpaceXformSteps>(srcCS, srcAT,
Mike Klein8f3d36c2018-08-14 10:28:05 -0400132 dstCS, kPremul_SkAlphaType)
Mike Kleinfcc10da2018-07-11 14:30:27 -0400133 ->apply(&p);
134 }
Mike Klein5cc9da62017-05-31 14:18:07 -0400135 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 {
Mike Klein45c16fa2017-07-18 18:15:13 -0400144 fSrcPtr.stride = fSource.rowBytesAsPixels();
Mike Klein548d3872018-01-24 15:36:35 -0500145
146 // We really want fSrcPtr.pixels = fSource.addr(-fLeft, -fTop) here, but that asserts.
147 // Instead we ask for addr(-fLeft+x, -fTop+y), then back up (x,y) manually.
148 // Representing bpp as a size_t keeps all this math in size_t instead of int,
149 // which could wrap around with large enough fSrcPtr.stride and y.
150 size_t bpp = fSource.info().bytesPerPixel();
151 fSrcPtr.pixels = (char*)fSource.addr(-fLeft+x, -fTop+y) - bpp * x
152 - bpp * y * fSrcPtr.stride;
Mike Klein5cc9da62017-05-31 14:18:07 -0400153
Mike Klein45c16fa2017-07-18 18:15:13 -0400154 fBlitter->blitRect(x,y,width,height);
Mike Klein5cc9da62017-05-31 14:18:07 -0400155 }
156
157private:
Mike Kleinb11ab572018-10-24 06:42:14 -0400158 SkArenaAlloc* fAlloc;
159 SkBlitter* fBlitter;
160 SkRasterPipeline_MemoryCtx fSrcPtr;
161 SkColor4f fPaintColor;
Mike Klein5cc9da62017-05-31 14:18:07 -0400162
163 typedef SkSpriteBlitter INHERITED;
164};
165
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166// returning null means the caller will call SkBlitter::Choose() and
167// have wrapped the source bitmap inside a shader
reedcb674142015-06-05 06:58:22 -0700168SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint,
Herb Derby57bfa022017-02-09 17:25:43 -0500169 const SkPixmap& source, int left, int top, SkArenaAlloc* allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170 /* We currently ignore antialiasing and filtertype, meaning we will take our
171 special blitters regardless of these settings. Ignoring filtertype seems fine
172 since by definition there is no scale in the matrix. Ignoring antialiasing is
173 a bit of a hack, since we "could" pass in the fractional left/top for the bitmap,
174 and respect that by blending the edges of the bitmap against the device. To support
175 this we could either add more special blitters here, or detect antialiasing in the
176 paint and return null if it is set, forcing the client to take the slow shader case
177 (which does respect soft edges).
178 */
halcanary96fcdcc2015-08-27 07:41:13 -0700179 SkASSERT(allocator != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180
herb58238462016-06-03 09:44:53 -0700181 if (source.alphaType() == kUnpremul_SkAlphaType) {
182 return nullptr;
183 }
184
herba62038c2016-05-26 10:56:17 -0700185 SkSpriteBlitter* blitter = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186
Mike Klein5cc9da62017-05-31 14:18:07 -0400187 if (!blitter && SkSpriteBlitter_Memcpy::Supports(dst, source, paint)) {
Mike Reed1919dc42017-05-31 09:25:18 -0400188 blitter = allocator->make<SkSpriteBlitter_Memcpy>(source);
Mike Klein5cc9da62017-05-31 14:18:07 -0400189 }
Mike Reedef8ce282017-10-05 16:04:41 -0400190 if (!blitter && !dst.colorSpace()) {
191 switch (dst.colorType()) {
192 case kN32_SkColorType:
193 blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator);
194 break;
195 case kRGB_565_SkColorType:
196 blitter = SkSpriteBlitter::ChooseL565(source, paint, allocator);
197 break;
198 case kAlpha_8_SkColorType:
199 blitter = SkSpriteBlitter::ChooseLA8(source, paint, allocator);
200 break;
201 default:
202 break;
203 }
Mike Klein5cc9da62017-05-31 14:18:07 -0400204 }
Mike Reed28266272018-01-17 23:04:04 -0500205 if (!blitter && !paint.getMaskFilter()) {
Mike Klein5cc9da62017-05-31 14:18:07 -0400206 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}