blob: 950f18791fe6be4b47ef80469df4e296c69382d9 [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
herba62038c2016-05-26 10:56:17 -07008#include "SkOpts.h"
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +00009#include "SkSmallAllocator.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkSpriteBlitter.h"
11
herb7df9e4a2016-06-10 13:01:27 -070012SkSpriteBlitter::SkSpriteBlitter(const SkPixmap& source)
13 : fSource(source) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000014
reedcb674142015-06-05 06:58:22 -070015void SkSpriteBlitter::setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) {
16 fDst = dst;
reed@android.com8a1c16f2008-12-17 15:59:43 +000017 fLeft = left;
18 fTop = top;
19 fPaint = &paint;
20}
21
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +000022void SkSpriteBlitter::blitH(int x, int y, int width) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000023 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070024
25 // Fallback to blitRect.
26 this->blitRect(x, y, width, 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +000027}
28
herb7df9e4a2016-06-10 13:01:27 -070029void SkSpriteBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000030 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070031
32 // No fallback strategy.
reed@android.com8a1c16f2008-12-17 15:59:43 +000033}
34
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +000035void SkSpriteBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000036 SkDEBUGFAIL("how did we get here?");
herb7df9e4a2016-06-10 13:01:27 -070037
38 // Fall back to superclass if the code gets here in release mode.
39 INHERITED::blitV(x, y, height, alpha);
reed@android.com8a1c16f2008-12-17 15:59:43 +000040}
41
herb7df9e4a2016-06-10 13:01:27 -070042void SkSpriteBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
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::blitMask(mask, clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +000047}
reed@android.com8a1c16f2008-12-17 15:59:43 +000048
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +000049///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000050
reed8c3fd4f2016-04-15 06:59:38 -070051// Only valid if...
52// 1. src == dst format
53// 2. paint has no modifiers (i.e. alpha, colorfilter, etc.)
54// 3. xfermode needs no blending: e.g. kSrc_Mode or kSrcOver_Mode + opaque src
55//
herb7df9e4a2016-06-10 13:01:27 -070056class SkSpriteBlitter_Src_SrcOver 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 }
reeddabe5d32016-06-21 10:28:14 -070062 if (dst.info().gammaCloseToSRGB() != src.info().gammaCloseToSRGB()) {
reed8c3fd4f2016-04-15 06:59:38 -070063 return false;
64 }
65 if (paint.getMaskFilter() || paint.getColorFilter() || paint.getImageFilter()) {
66 return false;
67 }
68 if (0xFF != paint.getAlpha()) {
69 return false;
70 }
71 SkXfermode::Mode mode;
72 if (!SkXfermode::AsMode(paint.getXfermode(), &mode)) {
73 return false;
74 }
75 if (SkXfermode::kSrc_Mode == mode) {
76 return true;
77 }
78 if (SkXfermode::kSrcOver_Mode == mode && src.isOpaque()) {
79 return true;
80 }
herba62038c2016-05-26 10:56:17 -070081
82 // At this point memcpy can't be used. The following check for using SrcOver.
83
reeddabe5d32016-06-21 10:28:14 -070084 if (dst.colorType() != kN32_SkColorType || !dst.info().gammaCloseToSRGB()) {
herba62038c2016-05-26 10:56:17 -070085 return false;
86 }
87
88 return SkXfermode::kSrcOver_Mode == mode;
reed8c3fd4f2016-04-15 06:59:38 -070089 }
90
herb7df9e4a2016-06-10 13:01:27 -070091 SkSpriteBlitter_Src_SrcOver(const SkPixmap& src)
92 : INHERITED(src) {}
reed8c3fd4f2016-04-15 06:59:38 -070093
94 void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override {
95 SkASSERT(Supports(dst, fSource, paint));
96 this->INHERITED::setup(dst, left, top, paint);
herba62038c2016-05-26 10:56:17 -070097 SkXfermode::Mode mode;
98 if (!SkXfermode::AsMode(paint.getXfermode(), &mode)) {
99 SkFAIL("Should never happen.");
100 }
101
102 SkASSERT(mode == SkXfermode::kSrcOver_Mode || mode == SkXfermode::kSrc_Mode);
103
104 if (mode == SkXfermode::kSrcOver_Mode && !fSource.isOpaque()) {
105 fUseMemcpy = false;
106 }
reed8c3fd4f2016-04-15 06:59:38 -0700107 }
108
109 void blitRect(int x, int y, int width, int height) override {
110 SkASSERT(fDst.colorType() == fSource.colorType());
reeddabe5d32016-06-21 10:28:14 -0700111 SkASSERT(fDst.info().gammaCloseToSRGB() == fSource.info().gammaCloseToSRGB());
reed8c3fd4f2016-04-15 06:59:38 -0700112 SkASSERT(width > 0 && height > 0);
113
herba62038c2016-05-26 10:56:17 -0700114 if (fUseMemcpy) {
115 char* dst = (char*)fDst.writable_addr(x, y);
116 const char* src = (const char*)fSource.addr(x - fLeft, y - fTop);
117 const size_t dstRB = fDst.rowBytes();
118 const size_t srcRB = fSource.rowBytes();
119 const size_t bytesToCopy = width << fSource.shiftPerPixel();
reed8c3fd4f2016-04-15 06:59:38 -0700120
herba62038c2016-05-26 10:56:17 -0700121 while (height --> 0) {
122 memcpy(dst, src, bytesToCopy);
123 dst += dstRB;
124 src += srcRB;
125 }
126 } else {
127 uint32_t* dst = fDst.writable_addr32(x, y);
128 const uint32_t* src = fSource.addr32(x - fLeft, y - fTop);
129 const int dstStride = fDst.rowBytesAsPixels();
130 const int srcStride = fSource.rowBytesAsPixels();
131
132 while (height --> 0) {
133 SkOpts::srcover_srgb_srgb(dst, src, width, width);
134 dst += dstStride;
135 src += srcStride;
136 }
reed8c3fd4f2016-04-15 06:59:38 -0700137 }
138 }
139
herba62038c2016-05-26 10:56:17 -0700140private:
reed8c3fd4f2016-04-15 06:59:38 -0700141 typedef SkSpriteBlitter INHERITED;
reed8c3fd4f2016-04-15 06:59:38 -0700142
herba62038c2016-05-26 10:56:17 -0700143 bool fUseMemcpy {true};
144};
reed8c3fd4f2016-04-15 06:59:38 -0700145
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146// returning null means the caller will call SkBlitter::Choose() and
147// have wrapped the source bitmap inside a shader
reedcb674142015-06-05 06:58:22 -0700148SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint,
reedc240e712015-05-23 12:26:41 -0700149 const SkPixmap& source, int left, int top, SkTBlitterAllocator* allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000150 /* We currently ignore antialiasing and filtertype, meaning we will take our
151 special blitters regardless of these settings. Ignoring filtertype seems fine
152 since by definition there is no scale in the matrix. Ignoring antialiasing is
153 a bit of a hack, since we "could" pass in the fractional left/top for the bitmap,
154 and respect that by blending the edges of the bitmap against the device. To support
155 this we could either add more special blitters here, or detect antialiasing in the
156 paint and return null if it is set, forcing the client to take the slow shader case
157 (which does respect soft edges).
158 */
halcanary96fcdcc2015-08-27 07:41:13 -0700159 SkASSERT(allocator != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160
herb58238462016-06-03 09:44:53 -0700161 // Defer to the general code if the pixels are unpremultipled. This case is not common,
162 // and this simplifies the code.
163 if (source.alphaType() == kUnpremul_SkAlphaType) {
164 return nullptr;
165 }
166
herba62038c2016-05-26 10:56:17 -0700167 SkSpriteBlitter* blitter = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168
herba62038c2016-05-26 10:56:17 -0700169 if (SkSpriteBlitter_Src_SrcOver::Supports(dst, source, paint)) {
170 blitter = allocator->createT<SkSpriteBlitter_Src_SrcOver>(source);
reed8c3fd4f2016-04-15 06:59:38 -0700171 } else {
172 switch (dst.colorType()) {
173 case kRGB_565_SkColorType:
174 blitter = SkSpriteBlitter::ChooseD16(source, paint, allocator);
175 break;
176 case kN32_SkColorType:
reeddabe5d32016-06-21 10:28:14 -0700177 if (dst.info().gammaCloseToSRGB()) {
reed8c3fd4f2016-04-15 06:59:38 -0700178 blitter = SkSpriteBlitter::ChooseS32(source, paint, allocator);
179 } else {
180 blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator);
181 }
182 break;
183 case kRGBA_F16_SkColorType:
184 blitter = SkSpriteBlitter::ChooseF16(source, paint, allocator);
185 break;
186 default:
reed8c3fd4f2016-04-15 06:59:38 -0700187 break;
188 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189 }
190
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000191 if (blitter) {
reedcb674142015-06-05 06:58:22 -0700192 blitter->setup(dst, left, top, paint);
mike@reedtribe.orgebe5bcd2011-04-20 11:01:37 +0000193 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194 return blitter;
195}