blob: 0fdb5e11b5c0c3ca0ce2893d8dbb82aa99e279b1 [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 "SkPM4fPriv.h"
15#include "SkRasterPipeline.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkSpriteBlitter.h"
Mike Klein45c16fa2017-07-18 18:15:13 -040017#include "../jumper/SkJumper.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000018
herb7df9e4a2016-06-10 13:01:27 -070019SkSpriteBlitter::SkSpriteBlitter(const SkPixmap& source)
20 : fSource(source) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000021
reedcb674142015-06-05 06:58:22 -070022void SkSpriteBlitter::setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) {
23 fDst = dst;
reed@android.com8a1c16f2008-12-17 15:59:43 +000024 fLeft = left;
25 fTop = top;
26 fPaint = &paint;
27}
28
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +000029void SkSpriteBlitter::blitH(int x, int y, int width) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000030 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070031
32 // Fallback to blitRect.
33 this->blitRect(x, y, width, 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +000034}
35
herb7df9e4a2016-06-10 13:01:27 -070036void SkSpriteBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000037 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070038
39 // No fallback strategy.
reed@android.com8a1c16f2008-12-17 15:59:43 +000040}
41
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +000042void SkSpriteBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000043 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070044
45 // Fall back to superclass if the code gets here in release mode.
46 INHERITED::blitV(x, y, height, alpha);
reed@android.com8a1c16f2008-12-17 15:59:43 +000047}
48
herb7df9e4a2016-06-10 13:01:27 -070049void SkSpriteBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000050 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070051
52 // Fall back to superclass if the code gets here in release mode.
53 INHERITED::blitMask(mask, clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +000054}
reed@android.com8a1c16f2008-12-17 15:59:43 +000055
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +000056///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000057
Mike Reed1919dc42017-05-31 09:25:18 -040058class SkSpriteBlitter_Memcpy final : public SkSpriteBlitter {
reed8c3fd4f2016-04-15 06:59:38 -070059public:
60 static bool Supports(const SkPixmap& dst, const SkPixmap& src, const SkPaint& paint) {
61 if (dst.colorType() != src.colorType()) {
62 return false;
63 }
Mike Klein23980332017-05-31 12:13:42 -040064 if (!SkColorSpace::Equals(dst.colorSpace(), src.colorSpace())) {
65 return false;
66 }
reed8c3fd4f2016-04-15 06:59:38 -070067 if (paint.getMaskFilter() || paint.getColorFilter() || paint.getImageFilter()) {
68 return false;
69 }
70 if (0xFF != paint.getAlpha()) {
71 return false;
72 }
reed374772b2016-10-05 17:33:02 -070073 SkBlendMode mode = paint.getBlendMode();
Mike Reed1919dc42017-05-31 09:25:18 -040074 return SkBlendMode::kSrc == mode || (SkBlendMode::kSrcOver == mode && src.isOpaque());
reed8c3fd4f2016-04-15 06:59:38 -070075 }
76
Mike Reed1919dc42017-05-31 09:25:18 -040077 SkSpriteBlitter_Memcpy(const SkPixmap& src)
herb7df9e4a2016-06-10 13:01:27 -070078 : INHERITED(src) {}
reed8c3fd4f2016-04-15 06:59:38 -070079
reed8c3fd4f2016-04-15 06:59:38 -070080 void blitRect(int x, int y, int width, int height) override {
81 SkASSERT(fDst.colorType() == fSource.colorType());
reed8c3fd4f2016-04-15 06:59:38 -070082 SkASSERT(width > 0 && height > 0);
83
Mike Reed1919dc42017-05-31 09:25:18 -040084 char* dst = (char*)fDst.writable_addr(x, y);
85 const char* src = (const char*)fSource.addr(x - fLeft, y - fTop);
86 const size_t dstRB = fDst.rowBytes();
87 const size_t srcRB = fSource.rowBytes();
88 const size_t bytesToCopy = width << fSource.shiftPerPixel();
reed8c3fd4f2016-04-15 06:59:38 -070089
Mike Reed1919dc42017-05-31 09:25:18 -040090 while (height --> 0) {
91 memcpy(dst, src, bytesToCopy);
92 dst += dstRB;
93 src += srcRB;
reed8c3fd4f2016-04-15 06:59:38 -070094 }
95 }
96
herba62038c2016-05-26 10:56:17 -070097private:
reed8c3fd4f2016-04-15 06:59:38 -070098 typedef SkSpriteBlitter INHERITED;
herba62038c2016-05-26 10:56:17 -070099};
reed8c3fd4f2016-04-15 06:59:38 -0700100
Mike Klein5cc9da62017-05-31 14:18:07 -0400101class SkRasterPipelineSpriteBlitter : public SkSpriteBlitter {
102public:
103 SkRasterPipelineSpriteBlitter(const SkPixmap& src, SkArenaAlloc* alloc)
104 : INHERITED(src)
105 , fAlloc(alloc)
106 , fBlitter(nullptr)
Mike Klein45c16fa2017-07-18 18:15:13 -0400107 , fSrcPtr{nullptr, 0}
Mike Klein5cc9da62017-05-31 14:18:07 -0400108 {}
109
Mike Klein5cc9da62017-05-31 14:18:07 -0400110 void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override {
111 fDst = dst;
112 fLeft = left;
113 fTop = top;
Mike Kleinbe569492018-09-14 09:34:21 -0400114 fPaintColor = paint.getColor4f();
Mike Klein5cc9da62017-05-31 14:18:07 -0400115
116 SkRasterPipeline p(fAlloc);
Mike Kleinafa35022018-09-17 16:41:26 -0400117 p.append_load(fSource.colorType(), &fSrcPtr);
Mike Klein9fb5a532018-09-13 15:23:38 -0400118
Mike Klein5cc9da62017-05-31 14:18:07 -0400119 if (fSource.colorType() == kAlpha_8_SkColorType) {
Mike Kleinfcc10da2018-07-11 14:30:27 -0400120 // The color for A8 images comes from the (sRGB) paint color.
Mike Kleinbe569492018-09-14 09:34:21 -0400121 p.append_set_rgb(fAlloc, fPaintColor);
Mike Klein5cc9da62017-05-31 14:18:07 -0400122 p.append(SkRasterPipeline::premul);
123 }
Mike Kleinfcc10da2018-07-11 14:30:27 -0400124 if (auto dstCS = fDst.colorSpace()) {
125 auto srcCS = fSource.colorSpace();
126 if (!srcCS || fSource.colorType() == kAlpha_8_SkColorType) {
127 // We treat untagged images as sRGB.
128 // A8 images get their r,g,b from the paint color, so they're also sRGB.
Mike Kleine28a6b52018-07-25 13:05:17 -0400129 srcCS = sk_srgb_singleton();
Mike Kleinfcc10da2018-07-11 14:30:27 -0400130 }
Mike Kleine28c7912018-08-14 11:49:34 -0400131 auto srcAT = fSource.isOpaque() ? kOpaque_SkAlphaType
132 : kPremul_SkAlphaType;
133 fAlloc->make<SkColorSpaceXformSteps>(srcCS, srcAT,
Mike Klein8f3d36c2018-08-14 10:28:05 -0400134 dstCS, kPremul_SkAlphaType)
Mike Kleinfcc10da2018-07-11 14:30:27 -0400135 ->apply(&p);
136 }
Mike Klein5cc9da62017-05-31 14:18:07 -0400137 if (fPaintColor.fA != 1.0f) {
138 p.append(SkRasterPipeline::scale_1_float, &fPaintColor.fA);
139 }
140
Mike Reedeb7dc792017-06-12 12:48:45 -0400141 bool is_opaque = fSource.isOpaque() && fPaintColor.fA == 1.0f;
142 fBlitter = SkCreateRasterPipelineBlitter(fDst, paint, p, is_opaque, fAlloc);
Mike Klein5cc9da62017-05-31 14:18:07 -0400143 }
144
145 void blitRect(int x, int y, int width, int height) override {
Mike Klein45c16fa2017-07-18 18:15:13 -0400146 fSrcPtr.stride = fSource.rowBytesAsPixels();
Mike Klein548d3872018-01-24 15:36:35 -0500147
148 // We really want fSrcPtr.pixels = fSource.addr(-fLeft, -fTop) here, but that asserts.
149 // Instead we ask for addr(-fLeft+x, -fTop+y), then back up (x,y) manually.
150 // Representing bpp as a size_t keeps all this math in size_t instead of int,
151 // which could wrap around with large enough fSrcPtr.stride and y.
152 size_t bpp = fSource.info().bytesPerPixel();
153 fSrcPtr.pixels = (char*)fSource.addr(-fLeft+x, -fTop+y) - bpp * x
154 - bpp * y * fSrcPtr.stride;
Mike Klein5cc9da62017-05-31 14:18:07 -0400155
Mike Klein45c16fa2017-07-18 18:15:13 -0400156 fBlitter->blitRect(x,y,width,height);
Mike Klein5cc9da62017-05-31 14:18:07 -0400157 }
158
159private:
Mike Klein45c16fa2017-07-18 18:15:13 -0400160 SkArenaAlloc* fAlloc;
161 SkBlitter* fBlitter;
162 SkJumper_MemoryCtx fSrcPtr;
163 SkColor4f fPaintColor;
Mike Klein5cc9da62017-05-31 14:18:07 -0400164
165 typedef SkSpriteBlitter INHERITED;
166};
167
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168// returning null means the caller will call SkBlitter::Choose() and
169// have wrapped the source bitmap inside a shader
reedcb674142015-06-05 06:58:22 -0700170SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint,
Herb Derby57bfa022017-02-09 17:25:43 -0500171 const SkPixmap& source, int left, int top, SkArenaAlloc* allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 /* We currently ignore antialiasing and filtertype, meaning we will take our
173 special blitters regardless of these settings. Ignoring filtertype seems fine
174 since by definition there is no scale in the matrix. Ignoring antialiasing is
175 a bit of a hack, since we "could" pass in the fractional left/top for the bitmap,
176 and respect that by blending the edges of the bitmap against the device. To support
177 this we could either add more special blitters here, or detect antialiasing in the
178 paint and return null if it is set, forcing the client to take the slow shader case
179 (which does respect soft edges).
180 */
halcanary96fcdcc2015-08-27 07:41:13 -0700181 SkASSERT(allocator != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182
herb58238462016-06-03 09:44:53 -0700183 if (source.alphaType() == kUnpremul_SkAlphaType) {
184 return nullptr;
185 }
186
herba62038c2016-05-26 10:56:17 -0700187 SkSpriteBlitter* blitter = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188
Mike Klein5cc9da62017-05-31 14:18:07 -0400189 if (!blitter && SkSpriteBlitter_Memcpy::Supports(dst, source, paint)) {
Mike Reed1919dc42017-05-31 09:25:18 -0400190 blitter = allocator->make<SkSpriteBlitter_Memcpy>(source);
Mike Klein5cc9da62017-05-31 14:18:07 -0400191 }
Mike Reedef8ce282017-10-05 16:04:41 -0400192 if (!blitter && !dst.colorSpace()) {
193 switch (dst.colorType()) {
194 case kN32_SkColorType:
195 blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator);
196 break;
197 case kRGB_565_SkColorType:
198 blitter = SkSpriteBlitter::ChooseL565(source, paint, allocator);
199 break;
200 case kAlpha_8_SkColorType:
201 blitter = SkSpriteBlitter::ChooseLA8(source, paint, allocator);
202 break;
203 default:
204 break;
205 }
Mike Klein5cc9da62017-05-31 14:18:07 -0400206 }
Mike Reed28266272018-01-17 23:04:04 -0500207 if (!blitter && !paint.getMaskFilter()) {
Mike Klein5cc9da62017-05-31 14:18:07 -0400208 blitter = allocator->make<SkRasterPipelineSpriteBlitter>(source, allocator);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209 }
210
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000211 if (blitter) {
reedcb674142015-06-05 06:58:22 -0700212 blitter->setup(dst, left, top, paint);
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000213 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214 return blitter;
215}