blob: 3a230029ce554af4ac9ffde103cc832bc3cc4032 [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);
116 switch (fSource.colorType()) {
117 case kAlpha_8_SkColorType: p.append(SkRasterPipeline::load_a8, &fSrcPtr); break;
118 case kGray_8_SkColorType: p.append(SkRasterPipeline::load_g8, &fSrcPtr); break;
119 case kRGB_565_SkColorType: p.append(SkRasterPipeline::load_565, &fSrcPtr); break;
120 case kARGB_4444_SkColorType: p.append(SkRasterPipeline::load_4444, &fSrcPtr); break;
Mike Kleinc2d20762017-06-27 19:53:21 -0400121 case kBGRA_8888_SkColorType: p.append(SkRasterPipeline::load_bgra, &fSrcPtr); break;
122 case kRGBA_8888_SkColorType: p.append(SkRasterPipeline::load_8888, &fSrcPtr); break;
Mike Klein5cc9da62017-05-31 14:18:07 -0400123 case kRGBA_F16_SkColorType: p.append(SkRasterPipeline::load_f16, &fSrcPtr); break;
124 default: SkASSERT(false);
125 }
126 if (fDst.colorSpace() &&
127 (!fSource.colorSpace() || fSource.colorSpace()->gammaCloseToSRGB())) {
128 p.append_from_srgb(fSource.alphaType());
129 }
Mike Klein5cc9da62017-05-31 14:18:07 -0400130 if (fSource.colorType() == kAlpha_8_SkColorType) {
131 p.append(SkRasterPipeline::set_rgb, &fPaintColor);
132 p.append(SkRasterPipeline::premul);
133 }
134 append_gamut_transform(&p, fAlloc,
135 fSource.colorSpace(), fDst.colorSpace(), kPremul_SkAlphaType);
136 if (fPaintColor.fA != 1.0f) {
137 p.append(SkRasterPipeline::scale_1_float, &fPaintColor.fA);
138 }
139
Mike Reedeb7dc792017-06-12 12:48:45 -0400140 bool is_opaque = fSource.isOpaque() && fPaintColor.fA == 1.0f;
141 fBlitter = SkCreateRasterPipelineBlitter(fDst, paint, p, is_opaque, fAlloc);
Mike Klein5cc9da62017-05-31 14:18:07 -0400142 }
143
144 void blitRect(int x, int y, int width, int height) override {
Mike Klein45c16fa2017-07-18 18:15:13 -0400145 int bpp = fSource.info().bytesPerPixel();
Mike Klein5cc9da62017-05-31 14:18:07 -0400146
Mike Klein45c16fa2017-07-18 18:15:13 -0400147 fSrcPtr.stride = fSource.rowBytesAsPixels();
148 fSrcPtr.pixels = (char*)fSource.addr(x-fLeft, y-fTop) - bpp * x
149 - bpp * y * fSrcPtr.stride;
Mike Klein5cc9da62017-05-31 14:18:07 -0400150
Mike Klein45c16fa2017-07-18 18:15:13 -0400151 fBlitter->blitRect(x,y,width,height);
Mike Klein5cc9da62017-05-31 14:18:07 -0400152 }
153
154private:
Mike Klein45c16fa2017-07-18 18:15:13 -0400155 SkArenaAlloc* fAlloc;
156 SkBlitter* fBlitter;
157 SkJumper_MemoryCtx fSrcPtr;
158 SkColor4f fPaintColor;
Mike Klein5cc9da62017-05-31 14:18:07 -0400159
160 typedef SkSpriteBlitter INHERITED;
161};
162
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163// returning null means the caller will call SkBlitter::Choose() and
164// have wrapped the source bitmap inside a shader
reedcb674142015-06-05 06:58:22 -0700165SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint,
Herb Derby57bfa022017-02-09 17:25:43 -0500166 const SkPixmap& source, int left, int top, SkArenaAlloc* allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167 /* We currently ignore antialiasing and filtertype, meaning we will take our
168 special blitters regardless of these settings. Ignoring filtertype seems fine
169 since by definition there is no scale in the matrix. Ignoring antialiasing is
170 a bit of a hack, since we "could" pass in the fractional left/top for the bitmap,
171 and respect that by blending the edges of the bitmap against the device. To support
172 this we could either add more special blitters here, or detect antialiasing in the
173 paint and return null if it is set, forcing the client to take the slow shader case
174 (which does respect soft edges).
175 */
halcanary96fcdcc2015-08-27 07:41:13 -0700176 SkASSERT(allocator != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177
herb58238462016-06-03 09:44:53 -0700178 if (source.alphaType() == kUnpremul_SkAlphaType) {
179 return nullptr;
180 }
181
herba62038c2016-05-26 10:56:17 -0700182 SkSpriteBlitter* blitter = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183
Mike Klein5cc9da62017-05-31 14:18:07 -0400184 if (!blitter && SkSpriteBlitter_Memcpy::Supports(dst, source, paint)) {
Mike Reed1919dc42017-05-31 09:25:18 -0400185 blitter = allocator->make<SkSpriteBlitter_Memcpy>(source);
Mike Klein5cc9da62017-05-31 14:18:07 -0400186 }
187 if (!blitter && !dst.colorSpace() && dst.colorType() == kN32_SkColorType) {
188 blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator);
189 }
Mike Reed262b3192017-07-17 10:13:58 -0400190 if (!blitter) {
Mike Klein5cc9da62017-05-31 14:18:07 -0400191 blitter = allocator->make<SkRasterPipelineSpriteBlitter>(source, allocator);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192 }
193
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000194 if (blitter) {
reedcb674142015-06-05 06:58:22 -0700195 blitter->setup(dst, left, top, paint);
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000196 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000197 return blitter;
198}